Merge remote-tracking branch 'public/pr/1970' into development
diff --git a/ChangeLog b/ChangeLog
index fb1e918..e6b4e26 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,56 @@
= mbed TLS x.x.x branch released xxxx-xx-xx
Bugfix
+ * Fix a bug in the update function for SSL ticket keys which previously
+ invalidated keys of a lifetime of less than a 1s. Fixes #1968.
+
+Changes
+ * Add tests for session resumption in DTLS.
+
+= mbed TLS 2.13.1 branch released 2018-09-06
+
+API Changes
+ * Extend the platform module with an abstraction mbedtls_platform_gmtime_r()
+ whose implementation should behave as a thread-safe version of gmtime().
+ This allows users to configure such an implementation at compile time when
+ the target system cannot be deduced automatically, by setting the option
+ MBEDTLS_PLATFORM_GMTIME_R_ALT. At this stage Mbed TLS is only able to
+ automatically select implementations for Windows and POSIX C libraries.
+
+Bugfix
+ * Fix build failures on platforms where only gmtime() is available but
+ neither gmtime_r() nor gmtime_s() are present. Fixes #1907.
+
+= mbed TLS 2.13.0 branch released 2018-08-31
+
+Security
+ * Fix an issue in the X.509 module which could lead to a buffer overread
+ during certificate extensions parsing. In case of receiving malformed
+ input (extensions length field equal to 0), an illegal read of one byte
+ beyond the input buffer is made. Found and analyzed by Nathan Crandall.
+
+Features
+ * Add support for fragmentation of outgoing DTLS handshake messages. This
+ is controlled by the maximum fragment length as set locally or negotiated
+ with the peer, as well as by a new per-connection MTU option, set using
+ mbedtls_ssl_set_mtu().
+ * Add support for auto-adjustment of MTU to a safe value during the
+ handshake when flights do not get through (RFC 6347, section 4.1.1.1,
+ last paragraph).
+ * Add support for packing multiple records within a single datagram,
+ enabled by default.
+ * Add support for buffering out-of-order handshake messages in DTLS.
+ The maximum amount of RAM used for this can be controlled by the
+ compile-time constant MBEDTLS_SSL_DTLS_MAX_BUFFERING defined
+ in mbedtls/config.h.
+
+API Changes
+ * Add function mbedtls_ssl_set_datagram_packing() to configure
+ the use of datagram packing (enabled by default).
+
+Bugfix
+ * Fix a potential memory leak in mbedtls_ssl_setup() function. An allocation
+ failure in the function could lead to other buffers being leaked.
* Fixes an issue with MBEDTLS_CHACHAPOLY_C which would not compile if
MBEDTLS_ARC4_C and MBEDTLS_CIPHER_NULL_CIPHER weren't also defined. #1890
* Fix a memory leak in ecp_mul_comb() if ecp_precompute_comb() fails.
@@ -10,11 +60,23 @@
* Add ecc extensions only if an ecc based ciphersuite is used.
This improves compliance to RFC 4492, and as a result, solves
interoperability issues with BouncyCastle. Raised by milenamil in #1157.
- * Replace printf with mbedtls_printf in aria. Found by TrinityTonic in #1908.
+ * Replace printf with mbedtls_printf in the ARIA module. Found by
+ TrinityTonic in #1908.
* Fix potential use-after-free in mbedtls_ssl_get_max_frag_len()
and mbedtls_ssl_get_record_expansion() after a session reset. Fixes #1941.
- * Fix a bug in the update function for SSL ticket keys which previously
- invalidated keys of a lifetime of less than a 1s. Fixes #1968.
+ * Fix a bug that caused SSL/TLS clients to incorrectly abort the handshake
+ with TLS versions 1.1 and earlier when the server requested authentication
+ without providing a list of CAs. This was due to an overly strict bounds
+ check in parsing the CertificateRequest message,
+ introduced in Mbed TLS 2.12.0. Fixes #1954.
+ * Fix a miscalculation of the maximum record expansion in
+ mbedtls_ssl_get_record_expansion() in case of ChachaPoly ciphersuites,
+ or CBC ciphersuites in (D)TLS versions 1.1 or higher. Fixes #1913, #1914.
+ * Fix undefined shifts with negative values in certificates parsing
+ (found by Catena cyber using oss-fuzz)
+ * Fix memory leak and free without initialization in pk_encrypt
+ and pk_decrypt example programs. Reported by Brace Stout. Fixes #1128.
+ * Remove redundant else statement. Raised by irwir. Fixes #1776.
Changes
* Copy headers preserving timestamps when doing a "make install".
@@ -23,7 +85,10 @@
Drozd. Fixes #1215 raised by randombit.
* Improve compatibility with some alternative CCM implementations by using
CCM test vectors from RAM.
- * Add tests for session resumption in DTLS.
+ * Add support for buffering of out-of-order handshake messages.
+ * Add warnings to the documentation of the HKDF module to reduce the risk
+ of misusing the mbedtls_hkdf_extract() and mbedtls_hkdf_expand()
+ functions. Fixes #1775. Reported by Brian J. Murray.
= mbed TLS 2.12.0 branch released 2018-07-25
diff --git a/doxygen/input/doc_mainpage.h b/doxygen/input/doc_mainpage.h
index f695dd2..b9f9ec1 100644
--- a/doxygen/input/doc_mainpage.h
+++ b/doxygen/input/doc_mainpage.h
@@ -24,7 +24,7 @@
*/
/**
- * @mainpage mbed TLS v2.12.0 source code documentation
+ * @mainpage mbed TLS v2.13.1 source code documentation
*
* This documentation describes the internal structure of mbed TLS. It was
* automatically generated from specially formatted comment blocks in
diff --git a/doxygen/mbedtls.doxyfile b/doxygen/mbedtls.doxyfile
index 317eb0d..2a87ada 100644
--- a/doxygen/mbedtls.doxyfile
+++ b/doxygen/mbedtls.doxyfile
@@ -28,7 +28,7 @@
# identify the project. Note that if you do not use Doxywizard you need
# to put quotes around the project name if it contains spaces.
-PROJECT_NAME = "mbed TLS v2.12.0"
+PROJECT_NAME = "mbed TLS v2.13.1"
# The PROJECT_NUMBER tag can be used to enter a project or revision number.
# This could be handy for archiving the generated documentation or
diff --git a/include/mbedtls/config.h b/include/mbedtls/config.h
index 70820be..81438c5 100644
--- a/include/mbedtls/config.h
+++ b/include/mbedtls/config.h
@@ -137,12 +137,21 @@
/**
* \def MBEDTLS_HAVE_TIME_DATE
*
- * System has time.h and time(), gmtime() and the clock is correct.
+ * System has time.h, time(), and an implementation for
+ * mbedtls_platform_gmtime_r() (see below).
* The time needs to be correct (not necesarily very accurate, but at least
* the date should be correct). This is used to verify the validity period of
* X.509 certificates.
*
* Comment if your system does not have a correct clock.
+ *
+ * \note mbedtls_platform_gmtime_r() is an abstraction in platform_util.h that
+ * behaves similarly to the gmtime_r() function from the C standard. Refer to
+ * the documentation for mbedtls_platform_gmtime_r() for more information.
+ *
+ * \note It is possible to configure an implementation for
+ * mbedtls_platform_gmtime_r() at compile-time by using the macro
+ * MBEDTLS_PLATFORM_GMTIME_R_ALT.
*/
#define MBEDTLS_HAVE_TIME_DATE
@@ -3010,6 +3019,23 @@
*/
//#define MBEDTLS_SSL_OUT_CONTENT_LEN 16384
+/** \def MBEDTLS_SSL_DTLS_MAX_BUFFERING
+ *
+ * Maximum number of heap-allocated bytes for the purpose of
+ * DTLS handshake message reassembly and future message buffering.
+ *
+ * This should be at least 9/8 * MBEDTLSSL_IN_CONTENT_LEN
+ * to account for a reassembled handshake message of maximum size,
+ * together with its reassembly bitmap.
+ *
+ * A value of 2 * MBEDTLS_SSL_IN_CONTENT_LEN (32768 by default)
+ * should be sufficient for all practical situations as it allows
+ * to reassembly a large handshake message (such as a certificate)
+ * while buffering multiple smaller handshake messages.
+ *
+ */
+//#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768
+
//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */
//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */
//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */
@@ -3083,6 +3109,25 @@
*/
//#define MBEDTLS_PLATFORM_ZEROIZE_ALT
+/**
+ * Uncomment the macro to let Mbed TLS use your alternate implementation of
+ * mbedtls_platform_gmtime_r(). This replaces the default implementation in
+ * platform_util.c.
+ *
+ * gmtime() is not a thread-safe function as defined in the C standard. The
+ * library will try to use safer implementations of this function, such as
+ * gmtime_r() when available. However, if Mbed TLS cannot identify the target
+ * system, the implementation of mbedtls_platform_gmtime_r() will default to
+ * using the standard gmtime(). In this case, calls from the library to
+ * gmtime() will be guarded by the global mutex mbedtls_threading_gmtime_mutex
+ * if MBEDTLS_THREADING_C is enabled. We recommend that calls from outside the
+ * library are also guarded with this mutex to avoid race conditions. However,
+ * if the macro MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, Mbed TLS will
+ * unconditionally use the implementation for mbedtls_platform_gmtime_r()
+ * supplied at compile time.
+ */
+//#define MBEDTLS_PLATFORM_GMTIME_R_ALT
+
/* \} name SECTION: Customisation configuration options */
/* Target and application specific configurations */
diff --git a/include/mbedtls/hkdf.h b/include/mbedtls/hkdf.h
index 6833e72..e6ed7cd 100644
--- a/include/mbedtls/hkdf.h
+++ b/include/mbedtls/hkdf.h
@@ -73,6 +73,11 @@
* \brief Take the input keying material \p ikm and extract from it a
* fixed-length pseudorandom key \p prk.
*
+ * \warning This function should only be used if the security of it has been
+ * studied and established in that particular context (eg. TLS 1.3
+ * key schedule). For standard HKDF security guarantees use
+ * \c mbedtls_hkdf instead.
+ *
* \param md A hash function; md.size denotes the length of the
* hash function output in bytes.
* \param salt An optional salt value (a non-secret random value);
@@ -97,10 +102,15 @@
* \brief Expand the supplied \p prk into several additional pseudorandom
* keys, which is the output of the HKDF.
*
+ * \warning This function should only be used if the security of it has been
+ * studied and established in that particular context (eg. TLS 1.3
+ * key schedule). For standard HKDF security guarantees use
+ * \c mbedtls_hkdf instead.
+ *
* \param md A hash function; md.size denotes the length of the hash
* function output in bytes.
- * \param prk A pseudorandom key of at least md.size bytes. \p prk is usually,
- * the output from the HKDF extract step.
+ * \param prk A pseudorandom key of at least md.size bytes. \p prk is
+ * usually the output from the HKDF extract step.
* \param prk_len The length in bytes of \p prk.
* \param info An optional context and application specific information
* string. This can be a zero-length string.
diff --git a/include/mbedtls/platform_util.h b/include/mbedtls/platform_util.h
index 84f0732..164a1a0 100644
--- a/include/mbedtls/platform_util.h
+++ b/include/mbedtls/platform_util.h
@@ -25,7 +25,17 @@
#ifndef MBEDTLS_PLATFORM_UTIL_H
#define MBEDTLS_PLATFORM_UTIL_H
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
#include <stddef.h>
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+#include "mbedtls/platform_time.h"
+#include <time.h>
+#endif /* MBEDTLS_HAVE_TIME_DATE */
#ifdef __cplusplus
extern "C" {
@@ -55,6 +65,37 @@
*/
void mbedtls_platform_zeroize( void *buf, size_t len );
+#if defined(MBEDTLS_HAVE_TIME_DATE)
+/**
+ * \brief Platform-specific implementation of gmtime_r()
+ *
+ * The function is a thread-safe abstraction that behaves
+ * similarly to the gmtime_r() function from Unix/POSIX.
+ *
+ * Mbed TLS will try to identify the underlying platform and
+ * make use of an appropriate underlying implementation (e.g.
+ * gmtime_r() for POSIX and gmtime_s() for Windows). If this is
+ * not possible, then gmtime() will be used. In this case, calls
+ * from the library to gmtime() will be guarded by the mutex
+ * mbedtls_threading_gmtime_mutex if MBEDTLS_THREADING_C is
+ * enabled. It is recommended that calls from outside the library
+ * are also guarded by this mutex.
+ *
+ * If MBEDTLS_PLATFORM_GMTIME_R_ALT is defined, then Mbed TLS will
+ * unconditionally use the alternative implementation for
+ * mbedtls_platform_gmtime_r() supplied by the user at compile time.
+ *
+ * \param tt Pointer to an object containing time (in seconds) since the
+ * epoch to be converted
+ * \param tm_buf Pointer to an object where the results will be stored
+ *
+ * \return Pointer to an object of type struct tm on success, otherwise
+ * NULL
+ */
+struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
+ struct tm *tm_buf );
+#endif /* MBEDTLS_HAVE_TIME_DATE */
+
#ifdef __cplusplus
}
#endif
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 2d511a8..83849a5 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -121,6 +121,7 @@
#define MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH -0x6600 /**< Couldn't set the hash for verifying CertificateVerify */
#define MBEDTLS_ERR_SSL_CONTINUE_PROCESSING -0x6580 /**< Internal-only message signaling that further message-processing should be done */
#define MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -0x6500 /**< The asynchronous operation is not completed yet. */
+#define MBEDTLS_ERR_SSL_EARLY_MESSAGE -0x6480 /**< Internal-only message signaling that a message arrived early. */
/*
* Various constants
@@ -242,6 +243,14 @@
#define MBEDTLS_SSL_OUT_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN
#endif
+/*
+ * Maximum number of heap-allocated bytes for the purpose of
+ * DTLS handshake message reassembly and future message buffering.
+ */
+#if !defined(MBEDTLS_SSL_DTLS_MAX_BUFFERING)
+#define MBEDTLS_SSL_DTLS_MAX_BUFFERING 32768
+#endif
+
/* \} name SECTION: Module settings */
/*
@@ -1022,14 +1031,14 @@
int renego_records_seen; /*!< Records since renego request, or with DTLS,
number of retransmissions of request if
renego_max_records is < 0 */
-#endif
+#endif /* MBEDTLS_SSL_RENEGOTIATION */
int major_ver; /*!< equal to MBEDTLS_SSL_MAJOR_VERSION_3 */
int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT)
unsigned badmac_seen; /*!< records with a bad MAC received */
-#endif
+#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
mbedtls_ssl_send_t *f_send; /*!< Callback for network send */
mbedtls_ssl_recv_t *f_recv; /*!< Callback for network receive */
@@ -1085,11 +1094,11 @@
uint16_t in_epoch; /*!< DTLS epoch for incoming records */
size_t next_record_offset; /*!< offset of the next record in datagram
(equal to in_left if none) */
-#endif
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
uint64_t in_window_top; /*!< last validated record seq_num */
uint64_t in_window; /*!< bitmask for replay detection */
-#endif
+#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */
size_t in_hslen; /*!< current handshake message length,
including the handshake header */
@@ -1098,6 +1107,11 @@
int keep_current_message; /*!< drop or reuse current message
on next call to record layer? */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ uint8_t disable_datagram_packing; /*!< Disable packing multiple records
+ * within a single datagram. */
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
/*
* Record layer (outgoing data)
*/
@@ -1112,12 +1126,18 @@
size_t out_msglen; /*!< record header: message length */
size_t out_left; /*!< amount of data not yet written */
+ unsigned char cur_out_ctr[8]; /*!< Outgoing record sequence number. */
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ uint16_t mtu; /*!< path mtu, used to fragment outgoing messages */
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
#if defined(MBEDTLS_ZLIB_SUPPORT)
unsigned char *compress_buf; /*!< zlib data buffer */
-#endif
+#endif /* MBEDTLS_ZLIB_SUPPORT */
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING)
signed char split_done; /*!< current record already splitted? */
-#endif
+#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */
/*
* PKI layer
@@ -1130,11 +1150,11 @@
#if defined(MBEDTLS_X509_CRT_PARSE_C)
char *hostname; /*!< expected peer CN for verification
(and SNI if available) */
-#endif
+#endif /* MBEDTLS_X509_CRT_PARSE_C */
#if defined(MBEDTLS_SSL_ALPN)
const char *alpn_chosen; /*!< negotiated protocol */
-#endif
+#endif /* MBEDTLS_SSL_ALPN */
/*
* Information for DTLS hello verify
@@ -1142,7 +1162,7 @@
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
unsigned char *cli_id; /*!< transport-level ID of the client */
size_t cli_id_len; /*!< length of cli_id */
-#endif
+#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */
/*
* Secure renegotiation
@@ -1154,7 +1174,7 @@
size_t verify_data_len; /*!< length of verify data stored */
char own_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */
char peer_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */
-#endif
+#endif /* MBEDTLS_SSL_RENEGOTIATION */
};
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
@@ -1374,6 +1394,52 @@
mbedtls_ssl_recv_t *f_recv,
mbedtls_ssl_recv_timeout_t *f_recv_timeout );
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+/**
+ * \brief Set the Maximum Tranport Unit (MTU).
+ * Special value: 0 means unset (no limit).
+ * This represents the maximum size of a datagram payload
+ * handled by the transport layer (usually UDP) as determined
+ * by the network link and stack. In practice, this controls
+ * the maximum size datagram the DTLS layer will pass to the
+ * \c f_send() callback set using \c mbedtls_ssl_set_bio().
+ *
+ * \note The limit on datagram size is converted to a limit on
+ * record payload by subtracting the current overhead of
+ * encapsulation and encryption/authentication if any.
+ *
+ * \note This can be called at any point during the connection, for
+ * example when a Path Maximum Transfer Unit (PMTU)
+ * estimate becomes available from other sources,
+ * such as lower (or higher) protocol layers.
+ *
+ * \note This setting only controls the size of the packets we send,
+ * and does not restrict the size of the datagrams we're
+ * willing to receive. Client-side, you can request the
+ * server to use smaller records with \c
+ * mbedtls_ssl_conf_max_frag_len().
+ *
+ * \note If both a MTU and a maximum fragment length have been
+ * configured (or negotiated with the peer), the resulting
+ * lower limit on record payload (see first note) is used.
+ *
+ * \note This can only be used to decrease the maximum size
+ * of datagrams (hence records, see first note) sent. It
+ * cannot be used to increase the maximum size of records over
+ * the limit set by #MBEDTLS_SSL_OUT_CONTENT_LEN.
+ *
+ * \note Values lower than the current record layer expansion will
+ * result in an error when trying to send data.
+ *
+ * \note Using record compression together with a non-zero MTU value
+ * will result in an error when trying to send data.
+ *
+ * \param ssl SSL context
+ * \param mtu Value of the path MTU in bytes
+ */
+void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu );
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
/**
* \brief Set the timeout period for mbedtls_ssl_read()
* (Default: no timeout.)
@@ -1757,6 +1823,38 @@
#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
+
+/**
+ * \brief Allow or disallow packing of multiple handshake records
+ * within a single datagram.
+ *
+ * \param ssl The SSL context to configure.
+ * \param allow_packing This determines whether datagram packing may
+ * be used or not. A value of \c 0 means that every
+ * record will be sent in a separate datagram; a
+ * value of \c 1 means that, if space permits,
+ * multiple handshake messages (including CCS) belonging to
+ * a single flight may be packed within a single datagram.
+ *
+ * \note This is enabled by default and should only be disabled
+ * for test purposes, or if datagram packing causes
+ * interoperability issues with peers that don't support it.
+ *
+ * \note Allowing datagram packing reduces the network load since
+ * there's less overhead if multiple messages share the same
+ * datagram. Also, it increases the handshake efficiency
+ * since messages belonging to a single datagram will not
+ * be reordered in transit, and so future message buffering
+ * or flight retransmission (if no buffering is used) as
+ * means to deal with reordering are needed less frequently.
+ *
+ * \note Application records are not affected by this option and
+ * are currently always sent in separate datagrams.
+ *
+ */
+void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl,
+ unsigned allow_packing );
+
/**
* \brief Set retransmit timeout values for the DTLS handshake.
* (DTLS only, no effect on TLS.)
@@ -2433,6 +2531,18 @@
* (Client: set maximum fragment length to emit *and*
* negotiate with the server during handshake)
*
+ * \note With TLS, this currently only affects ApplicationData (sent
+ * with \c mbedtls_ssl_read()), not handshake messages.
+ * With DTLS, this affects both ApplicationData and handshake.
+ *
+ * \note This sets the maximum length for a record's payload,
+ * excluding record overhead that will be added to it, see
+ * \c mbedtls_ssl_get_record_expansion().
+ *
+ * \note For DTLS, it is also possible to set a limit for the total
+ * size of daragrams passed to the transport layer, including
+ * record overhead, see \c mbedtls_ssl_set_mtu().
+ *
* \param conf SSL configuration
* \param mfl_code Code for maximum fragment length (allowed values:
* MBEDTLS_SSL_MAX_FRAG_LEN_512, MBEDTLS_SSL_MAX_FRAG_LEN_1024,
@@ -2695,6 +2805,9 @@
* \brief Return the (maximum) number of bytes added by the record
* layer: header + encryption/MAC overhead (inc. padding)
*
+ * \note This function is not available (always returns an error)
+ * when record compression is enabled.
+ *
* \param ssl SSL context
*
* \return Current maximum record expansion in bytes, or
@@ -2709,12 +2822,8 @@
* This is the value negotiated with peer if any,
* or the locally configured value.
*
- * \note With DTLS, \c mbedtls_ssl_write() will return an error if
- * called with a larger length value.
- * With TLS, \c mbedtls_ssl_write() will fragment the input if
- * necessary and return the number of bytes written; it is up
- * to the caller to call \c mbedtls_ssl_write() again in
- * order to send the remaining bytes if any.
+ * \sa mbedtls_ssl_conf_max_frag_len()
+ * \sa mbedtls_ssl_get_max_record_payload()
*
* \param ssl SSL context
*
@@ -2723,6 +2832,34 @@
size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl );
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
+/**
+ * \brief Return the current maximum outgoing record payload in bytes.
+ * This takes into account the config.h setting \c
+ * MBEDTLS_SSL_OUT_CONTENT_LEN, the configured and negotiated
+ * max fragment length extension if used, and for DTLS the
+ * path MTU as configured and current record expansion.
+ *
+ * \note With DTLS, \c mbedtls_ssl_write() will return an error if
+ * called with a larger length value.
+ * With TLS, \c mbedtls_ssl_write() will fragment the input if
+ * necessary and return the number of bytes written; it is up
+ * to the caller to call \c mbedtls_ssl_write() again in
+ * order to send the remaining bytes if any.
+ *
+ * \note This function is not available (always returns an error)
+ * when record compression is enabled.
+ *
+ * \sa mbedtls_ssl_set_mtu()
+ * \sa mbedtls_ssl_get_max_frag_len()
+ * \sa mbedtls_ssl_get_record_expansion()
+ *
+ * \param ssl SSL context
+ *
+ * \return Current maximum payload for an outgoing record,
+ * or a negative error code.
+ */
+int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl );
+
#if defined(MBEDTLS_X509_CRT_PARSE_C)
/**
* \brief Return the peer certificate from the current connection
diff --git a/include/mbedtls/ssl_internal.h b/include/mbedtls/ssl_internal.h
index d214703..4b4417a 100644
--- a/include/mbedtls/ssl_internal.h
+++ b/include/mbedtls/ssl_internal.h
@@ -155,6 +155,9 @@
#define MBEDTLS_SSL_OUT_PAYLOAD_LEN ( MBEDTLS_SSL_PAYLOAD_OVERHEAD + \
( MBEDTLS_SSL_OUT_CONTENT_LEN ) )
+/* The maximum number of buffered handshake messages. */
+#define MBEDTLS_SSL_MAX_BUFFERED_HS 4
+
/* Maximum length we can advertise as our max content length for
RFC 6066 max_fragment_length extension negotiation purposes
(the lesser of both sizes, if they are unequal.)
@@ -294,18 +297,45 @@
unsigned char verify_cookie_len; /*!< Cli: cookie length
Srv: flag for sending a cookie */
- unsigned char *hs_msg; /*!< Reassembled handshake message */
-
uint32_t retransmit_timeout; /*!< Current value of timeout */
unsigned char retransmit_state; /*!< Retransmission state */
- mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */
- mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */
+ mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */
+ mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */
+ unsigned char *cur_msg_p; /*!< Position in current message */
unsigned int in_flight_start_seq; /*!< Minimum message sequence in the
flight being received */
mbedtls_ssl_transform *alt_transform_out; /*!< Alternative transform for
resending messages */
unsigned char alt_out_ctr[8]; /*!< Alternative record epoch/counter
for resending messages */
+
+ struct
+ {
+ size_t total_bytes_buffered; /*!< Cumulative size of heap allocated
+ * buffers used for message buffering. */
+
+ uint8_t seen_ccs; /*!< Indicates if a CCS message has
+ * been seen in the current flight. */
+
+ struct mbedtls_ssl_hs_buffer
+ {
+ unsigned is_valid : 1;
+ unsigned is_fragmented : 1;
+ unsigned is_complete : 1;
+ unsigned char *data;
+ size_t data_len;
+ } hs[MBEDTLS_SSL_MAX_BUFFERED_HS];
+
+ struct
+ {
+ unsigned char *data;
+ size_t len;
+ unsigned epoch;
+ } future_record;
+
+ } buffering;
+
+ uint16_t mtu; /*!< Handshake mtu, used to fragment outgoing messages */
#endif /* MBEDTLS_SSL_PROTO_DTLS */
/*
@@ -364,6 +394,8 @@
#endif /* MBEDTLS_SSL_ASYNC_PRIVATE */
};
+typedef struct mbedtls_ssl_hs_buffer mbedtls_ssl_hs_buffer;
+
/*
* This structure contains a full set of runtime transform parameters
* either in negotiation or active.
@@ -478,7 +510,6 @@
void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl );
int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl );
-int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl );
int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl );
int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl );
void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl );
@@ -490,7 +521,10 @@
* of the logic of (D)TLS from the implementation
* of the secure transport.
*
- * \param ssl SSL context to use
+ * \param ssl The SSL context to use.
+ * \param update_hs_digest This indicates if the handshake digest
+ * should be automatically updated in case
+ * a handshake message is found.
*
* \return 0 or non-zero error code.
*
@@ -556,10 +590,12 @@
* following the above definition.
*
*/
-int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl );
+int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
+ unsigned update_hs_digest );
int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want );
-int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl );
+int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl );
+int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush );
int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl );
int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl );
@@ -668,6 +704,7 @@
void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl );
void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl );
int mbedtls_ssl_resend( mbedtls_ssl_context *ssl );
+int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl );
#endif
/* Visible for testing purposes only */
diff --git a/include/mbedtls/threading.h b/include/mbedtls/threading.h
index 5112ebb..75298bf 100644
--- a/include/mbedtls/threading.h
+++ b/include/mbedtls/threading.h
@@ -99,6 +99,17 @@
#if defined(MBEDTLS_FS_IO)
extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex;
#endif
+
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+/* This mutex may or may not be used in the default definition of
+ * mbedtls_platform_gmtime_r(), but in order to determine that,
+ * we need to check POSIX features, hence modify _POSIX_C_SOURCE.
+ * With the current approach, this declaration is orphaned, lacking
+ * an accompanying definition, in case mbedtls_platform_gmtime_r()
+ * doesn't need it, but that's not a problem. */
+extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex;
+#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
+
#endif /* MBEDTLS_THREADING_C */
#ifdef __cplusplus
diff --git a/include/mbedtls/version.h b/include/mbedtls/version.h
index eaf25d9..326b8bd 100644
--- a/include/mbedtls/version.h
+++ b/include/mbedtls/version.h
@@ -39,17 +39,17 @@
* Major, Minor, Patchlevel
*/
#define MBEDTLS_VERSION_MAJOR 2
-#define MBEDTLS_VERSION_MINOR 12
-#define MBEDTLS_VERSION_PATCH 0
+#define MBEDTLS_VERSION_MINOR 13
+#define MBEDTLS_VERSION_PATCH 1
/**
* The single version number has the following structure:
* MMNNPP00
* Major version | Minor version | Patch version
*/
-#define MBEDTLS_VERSION_NUMBER 0x020C0000
-#define MBEDTLS_VERSION_STRING "2.12.0"
-#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.12.0"
+#define MBEDTLS_VERSION_NUMBER 0x020D0100
+#define MBEDTLS_VERSION_STRING "2.13.1"
+#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.13.1"
#if defined(MBEDTLS_VERSION_C)
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 5115b96..275eda3 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -159,15 +159,15 @@
if(USE_SHARED_MBEDTLS_LIBRARY)
add_library(mbedcrypto SHARED ${src_crypto})
- set_target_properties(mbedcrypto PROPERTIES VERSION 2.12.0 SOVERSION 3)
+ set_target_properties(mbedcrypto PROPERTIES VERSION 2.13.1 SOVERSION 3)
target_link_libraries(mbedcrypto ${libs})
add_library(mbedx509 SHARED ${src_x509})
- set_target_properties(mbedx509 PROPERTIES VERSION 2.12.0 SOVERSION 0)
+ set_target_properties(mbedx509 PROPERTIES VERSION 2.13.1 SOVERSION 0)
target_link_libraries(mbedx509 ${libs} mbedcrypto)
add_library(mbedtls SHARED ${src_tls})
- set_target_properties(mbedtls PROPERTIES VERSION 2.12.0 SOVERSION 11)
+ set_target_properties(mbedtls PROPERTIES VERSION 2.13.1 SOVERSION 12)
target_link_libraries(mbedtls ${libs} mbedx509)
install(TARGETS mbedtls mbedx509 mbedcrypto
diff --git a/library/Makefile b/library/Makefile
index ac88d4c..430c598 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -35,7 +35,7 @@
endif
endif
-SOEXT_TLS=so.11
+SOEXT_TLS=so.12
SOEXT_X509=so.0
SOEXT_CRYPTO=so.3
diff --git a/library/ecp.c b/library/ecp.c
index 68c6f49..9e2c085 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -1897,7 +1897,6 @@
mbedtls_mpi_get_bit( d, 1 ) != 0 ||
mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */
return( MBEDTLS_ERR_ECP_INVALID_KEY );
- else
/* see [Curve25519] page 5 */
if( grp->nbits == 254 && mbedtls_mpi_get_bit( d, 2 ) != 0 )
diff --git a/library/error.c b/library/error.c
index 774244b..6c88689 100644
--- a/library/error.c
+++ b/library/error.c
@@ -515,6 +515,8 @@
mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that further message-processing should be done" );
if( use_ret == -(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) )
mbedtls_snprintf( buf, buflen, "SSL - The asynchronous operation is not completed yet" );
+ if( use_ret == -(MBEDTLS_ERR_SSL_EARLY_MESSAGE) )
+ mbedtls_snprintf( buf, buflen, "SSL - Internal-only message signaling that a message arrived early" );
#endif /* MBEDTLS_SSL_TLS_C */
#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C)
diff --git a/library/platform_util.c b/library/platform_util.c
index 1a57de9..ca5fe4f 100644
--- a/library/platform_util.c
+++ b/library/platform_util.c
@@ -20,6 +20,14 @@
* This file is part of Mbed TLS (https://tls.mbed.org)
*/
+/*
+ * Ensure gmtime_r is available even with -std=c99; must be defined before
+ * config.h, which pulls in glibc's features.h. Harmless on other platforms.
+ */
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
@@ -27,6 +35,7 @@
#endif
#include "mbedtls/platform_util.h"
+#include "mbedtls/threading.h"
#include <stddef.h>
#include <string.h>
@@ -65,3 +74,62 @@
memset_func( buf, 0, len );
}
#endif /* MBEDTLS_PLATFORM_ZEROIZE_ALT */
+
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+#include <time.h>
+#if !defined(_WIN32) && (defined(unix) || \
+ defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
+ defined(__MACH__)))
+#include <unistd.h>
+#endif /* !_WIN32 && (unix || __unix || __unix__ ||
+ * (__APPLE__ && __MACH__)) */
+
+#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
+ ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+/*
+ * This is a convenience shorthand macro to avoid checking the long
+ * preprocessor conditions above. Ideally, we could expose this macro in
+ * platform_util.h and simply use it in platform_util.c, threading.c and
+ * threading.h. However, this macro is not part of the Mbed TLS public API, so
+ * we keep it private by only defining it in this file
+ */
+#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
+#define PLATFORM_UTIL_USE_GMTIME
+#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
+
+#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
+ ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+
+struct tm *mbedtls_platform_gmtime_r( const mbedtls_time_t *tt,
+ struct tm *tm_buf )
+{
+#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
+ return( ( gmtime_s( tm_buf, tt ) == 0 ) ? tm_buf : NULL );
+#elif !defined(PLATFORM_UTIL_USE_GMTIME)
+ return( gmtime_r( tt, tm_buf ) );
+#else
+ struct tm *lt;
+
+#if defined(MBEDTLS_THREADING_C)
+ if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 )
+ return( NULL );
+#endif /* MBEDTLS_THREADING_C */
+
+ lt = gmtime( tt );
+
+ if( lt != NULL )
+ {
+ memcpy( tm_buf, lt, sizeof( struct tm ) );
+ }
+
+#if defined(MBEDTLS_THREADING_C)
+ if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 )
+ return( NULL );
+#endif /* MBEDTLS_THREADING_C */
+
+ return( ( lt == NULL ) ? NULL : tm_buf );
+#endif /* _WIN32 && !EFIX64 && !EFI32 */
+}
+#endif /* MBEDTLS_HAVE_TIME_DATE && MBEDTLS_PLATFORM_GMTIME_R_ALT */
diff --git a/library/ssl_cli.c b/library/ssl_cli.c
index 321d636..8385720 100644
--- a/library/ssl_cli.c
+++ b/library/ssl_cli.c
@@ -1088,12 +1088,21 @@
mbedtls_ssl_send_flight_completed( ssl );
#endif
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
+ return( ret );
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client hello" ) );
return( 0 );
@@ -1491,7 +1500,7 @@
buf = ssl->in_msg;
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
/* No alert on a read error. */
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
@@ -2340,7 +2349,7 @@
#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED ||
MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
@@ -2647,7 +2656,7 @@
return( 0 );
}
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
@@ -2721,7 +2730,7 @@
* therefore the buffer length at this point must be greater than that
* regardless of the actual code path.
*/
- if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n )
+ if( ssl->in_hslen <= mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) );
mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
@@ -2799,7 +2808,7 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) );
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
@@ -3075,9 +3084,9 @@
ssl->state++;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
@@ -3260,9 +3269,9 @@
ssl->state++;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
@@ -3288,7 +3297,7 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) );
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
@@ -3323,8 +3332,8 @@
msg = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl );
- lifetime = ( msg[0] << 24 ) | ( msg[1] << 16 ) |
- ( msg[2] << 8 ) | ( msg[3] );
+ lifetime = ( ((uint32_t) msg[0]) << 24 ) | ( msg[1] << 16 ) |
+ ( msg[2] << 8 ) | ( msg[3] );
ticket_len = ( msg[4] << 8 ) | ( msg[5] );
@@ -3402,10 +3411,10 @@
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
{
- if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
return( ret );
}
-#endif
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
/* Change state now, so that it is right in mbedtls_ssl_read_record(), used
* by DTLS for dropping out-of-sequence ChangeCipherSpec records */
diff --git a/library/ssl_srv.c b/library/ssl_srv.c
index 2872f1f..36ca0d6 100644
--- a/library/ssl_srv.c
+++ b/library/ssl_srv.c
@@ -1294,7 +1294,7 @@
return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO );
}
- memcpy( ssl->out_ctr + 2, ssl->in_ctr + 2, 6 );
+ memcpy( ssl->cur_out_ctr + 2, ssl->in_ctr + 2, 6 );
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
if( mbedtls_ssl_dtls_replay_check( ssl ) != 0 )
@@ -2384,12 +2384,21 @@
ssl->state = MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
+ return( ret );
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello verify request" ) );
return( 0 );
@@ -2624,7 +2633,7 @@
ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO;
- ret = mbedtls_ssl_write_record( ssl );
+ ret = mbedtls_ssl_write_handshake_msg( ssl );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) );
@@ -2819,7 +2828,7 @@
ssl->out_msg[4 + ct_len + sa_len] = (unsigned char)( total_dn_size >> 8 );
ssl->out_msg[5 + ct_len + sa_len] = (unsigned char)( total_dn_size );
- ret = mbedtls_ssl_write_record( ssl );
+ ret = mbedtls_ssl_write_handshake_msg( ssl );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) );
@@ -3336,9 +3345,9 @@
ssl->state++;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
@@ -3363,12 +3372,21 @@
mbedtls_ssl_send_flight_completed( ssl );
#endif
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
+ return( ret );
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello done" ) );
return( 0 );
@@ -3710,7 +3728,7 @@
}
else
#endif
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
@@ -4020,25 +4038,10 @@
}
/* Read the message without adding it to the checksum */
- do {
-
- do ret = mbedtls_ssl_read_record_layer( ssl );
- while( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING );
-
- if( ret != 0 )
- {
- MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret );
- return( ret );
- }
-
- ret = mbedtls_ssl_handle_message_type( ssl );
-
- } while( MBEDTLS_ERR_SSL_NON_FATAL == ret ||
- MBEDTLS_ERR_SSL_CONTINUE_PROCESSING == ret );
-
+ ret = mbedtls_ssl_read_record( ssl, 0 /* no checksum update */ );
if( 0 != ret )
{
- MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record" ), ret );
return( ret );
}
@@ -4227,9 +4230,9 @@
*/
ssl->handshake->new_session_ticket = 0;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
@@ -4258,10 +4261,10 @@
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
{
- if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
return( ret );
}
-#endif
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
switch( ssl->state )
{
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 3b047fc..8bd74db 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -54,6 +54,9 @@
#include "mbedtls/oid.h"
#endif
+static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl );
+static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl );
+
/* Length of the "epoch" field in the record header */
static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl )
{
@@ -96,7 +99,101 @@
return( 0 );
}
+static void ssl_update_out_pointers( mbedtls_ssl_context *ssl,
+ mbedtls_ssl_transform *transform );
+static void ssl_update_in_pointers( mbedtls_ssl_context *ssl,
+ mbedtls_ssl_transform *transform );
+
+#define SSL_DONT_FORCE_FLUSH 0
+#define SSL_FORCE_FLUSH 1
+
#if defined(MBEDTLS_SSL_PROTO_DTLS)
+
+/* Forward declarations for functions related to message buffering. */
+static void ssl_buffering_free( mbedtls_ssl_context *ssl );
+static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl,
+ uint8_t slot );
+static void ssl_free_buffered_record( mbedtls_ssl_context *ssl );
+static int ssl_load_buffered_message( mbedtls_ssl_context *ssl );
+static int ssl_load_buffered_record( mbedtls_ssl_context *ssl );
+static int ssl_buffer_message( mbedtls_ssl_context *ssl );
+static int ssl_buffer_future_record( mbedtls_ssl_context *ssl );
+static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl );
+
+static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl );
+static size_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl )
+{
+ size_t mtu = ssl_get_current_mtu( ssl );
+
+ if( mtu != 0 && mtu < MBEDTLS_SSL_OUT_BUFFER_LEN )
+ return( mtu );
+
+ return( MBEDTLS_SSL_OUT_BUFFER_LEN );
+}
+
+static int ssl_get_remaining_space_in_datagram( mbedtls_ssl_context const *ssl )
+{
+ size_t const bytes_written = ssl->out_left;
+ size_t const mtu = ssl_get_maximum_datagram_size( ssl );
+
+ /* Double-check that the write-index hasn't gone
+ * past what we can transmit in a single datagram. */
+ if( bytes_written > mtu )
+ {
+ /* Should never happen... */
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ return( (int) ( mtu - bytes_written ) );
+}
+
+static int ssl_get_remaining_payload_in_datagram( mbedtls_ssl_context const *ssl )
+{
+ int ret;
+ size_t remaining, expansion;
+ size_t max_len = MBEDTLS_SSL_MAX_CONTENT_LEN;
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl );
+
+ if( max_len > mfl )
+ max_len = mfl;
+
+ /* By the standard (RFC 6066 Sect. 4), the MFL extension
+ * only limits the maximum record payload size, so in theory
+ * we would be allowed to pack multiple records of payload size
+ * MFL into a single datagram. However, this would mean that there's
+ * no way to explicitly communicate MTU restrictions to the peer.
+ *
+ * The following reduction of max_len makes sure that we never
+ * write datagrams larger than MFL + Record Expansion Overhead.
+ */
+ if( max_len <= ssl->out_left )
+ return( 0 );
+
+ max_len -= ssl->out_left;
+#endif
+
+ ret = ssl_get_remaining_space_in_datagram( ssl );
+ if( ret < 0 )
+ return( ret );
+ remaining = (size_t) ret;
+
+ ret = mbedtls_ssl_get_record_expansion( ssl );
+ if( ret < 0 )
+ return( ret );
+ expansion = (size_t) ret;
+
+ if( remaining <= expansion )
+ return( 0 );
+
+ remaining -= expansion;
+ if( remaining >= max_len )
+ remaining = max_len;
+
+ return( (int) remaining );
+}
+
/*
* Double the retransmit timeout value, within the allowed range,
* returning -1 if the maximum value has already been reached.
@@ -108,6 +205,15 @@
if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max )
return( -1 );
+ /* Implement the final paragraph of RFC 6347 section 4.1.1.1
+ * in the following way: after the initial transmission and a first
+ * retransmission, back off to a temporary estimated MTU of 508 bytes.
+ * This value is guaranteed to be deliverable (if not guaranteed to be
+ * delivered) of any compliant IPv4 (and IPv6) network, and should work
+ * on most non-IP stacks too. */
+ if( ssl->handshake->retransmit_timeout != ssl->conf->hs_timeout_min )
+ ssl->handshake->mtu = 508;
+
new_timeout = 2 * ssl->handshake->retransmit_timeout;
/* Avoid arithmetic overflow and range overflow */
@@ -1345,14 +1451,6 @@
MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload",
ssl->out_msg, ssl->out_msglen );
- if( ssl->out_msglen > MBEDTLS_SSL_OUT_CONTENT_LEN )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record content %u too large, maximum %d",
- (unsigned) ssl->out_msglen,
- MBEDTLS_SSL_OUT_CONTENT_LEN ) );
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
- }
-
/*
* Add MAC before if needed
*/
@@ -1626,6 +1724,8 @@
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC)
if( auth_done == 0 )
{
+ unsigned char mac[MBEDTLS_SSL_MAC_ADD];
+
/*
* MAC(MAC_write_key, seq_num +
* TLSCipherText.type +
@@ -1648,10 +1748,12 @@
mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, pseudo_hdr, 13 );
mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc,
ssl->out_iv, ssl->out_msglen );
- mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc,
- ssl->out_iv + ssl->out_msglen );
+ mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, mac );
mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc );
+ memcpy( ssl->out_iv + ssl->out_msglen, mac,
+ ssl->transform_out->maclen );
+
ssl->out_msglen += ssl->transform_out->maclen;
auth_done++;
}
@@ -2644,7 +2746,7 @@
int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl )
{
int ret;
- unsigned char *buf, i;
+ unsigned char *buf;
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) );
@@ -2667,8 +2769,7 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d",
mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) );
- buf = ssl->out_hdr + mbedtls_ssl_hdr_len( ssl ) +
- ssl->out_msglen - ssl->out_left;
+ buf = ssl->out_hdr - ssl->out_left;
ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left );
MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret );
@@ -2687,16 +2788,17 @@
ssl->out_left -= ret;
}
- for( i = 8; i > ssl_ep_len( ssl ); i-- )
- if( ++ssl->out_ctr[i - 1] != 0 )
- break;
-
- /* The loop goes to its end iff the counter is wrapping */
- if( i == ssl_ep_len( ssl ) )
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
{
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) );
- return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
+ ssl->out_hdr = ssl->out_buf;
}
+ else
+#endif
+ {
+ ssl->out_hdr = ssl->out_buf + 8;
+ }
+ ssl_update_out_pointers( ssl, ssl->transform_out );
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) );
@@ -2713,6 +2815,9 @@
static int ssl_flight_append( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_flight_item *msg;
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_flight_append" ) );
+ MBEDTLS_SSL_DEBUG_BUF( 4, "message appended to flight",
+ ssl->out_msg, ssl->out_msglen );
/* Allocate space for current message */
if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL )
@@ -2746,6 +2851,7 @@
cur->next = msg;
}
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_flight_append" ) );
return( 0 );
}
@@ -2794,19 +2900,12 @@
ssl->handshake->alt_transform_out = tmp_transform;
/* Swap epoch + sequence_number */
- memcpy( tmp_out_ctr, ssl->out_ctr, 8 );
- memcpy( ssl->out_ctr, ssl->handshake->alt_out_ctr, 8 );
+ memcpy( tmp_out_ctr, ssl->cur_out_ctr, 8 );
+ memcpy( ssl->cur_out_ctr, ssl->handshake->alt_out_ctr, 8 );
memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 );
/* Adjust to the newly activated transform */
- if( ssl->transform_out != NULL &&
- ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
- {
- ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen -
- ssl->transform_out->fixed_ivlen;
- }
- else
- ssl->out_msg = ssl->out_iv;
+ ssl_update_out_pointers( ssl, ssl->transform_out );
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_activate != NULL )
@@ -2822,20 +2921,38 @@
/*
* Retransmit the current flight of messages.
+ */
+int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
+{
+ int ret = 0;
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) );
+
+ ret = mbedtls_ssl_flight_transmit( ssl );
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) );
+
+ return( ret );
+}
+
+/*
+ * Transmit or retransmit the current flight of messages.
*
* Need to remember the current message in case flush_output returns
* WANT_WRITE, causing us to exit this function and come back later.
* This function must be called until state is no longer SENDING.
*/
-int mbedtls_ssl_resend( mbedtls_ssl_context *ssl )
+int mbedtls_ssl_flight_transmit( mbedtls_ssl_context *ssl )
{
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) );
+ int ret;
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_flight_transmit" ) );
if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING )
{
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise resending" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise flight transmission" ) );
ssl->handshake->cur_msg = ssl->handshake->flight;
+ ssl->handshake->cur_msg_p = ssl->handshake->flight->p + 12;
ssl_swap_epochs( ssl );
ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING;
@@ -2843,33 +2960,129 @@
while( ssl->handshake->cur_msg != NULL )
{
- int ret;
- mbedtls_ssl_flight_item *cur = ssl->handshake->cur_msg;
+ size_t max_frag_len;
+ const mbedtls_ssl_flight_item * const cur = ssl->handshake->cur_msg;
+
+ int const is_finished =
+ ( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE &&
+ cur->p[0] == MBEDTLS_SSL_HS_FINISHED );
+
+ uint8_t const force_flush = ssl->disable_datagram_packing == 1 ?
+ SSL_FORCE_FLUSH : SSL_DONT_FORCE_FLUSH;
/* Swap epochs before sending Finished: we can't do it after
* sending ChangeCipherSpec, in case write returns WANT_READ.
* Must be done before copying, may change out_msg pointer */
- if( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE &&
- cur->p[0] == MBEDTLS_SSL_HS_FINISHED )
+ if( is_finished && ssl->handshake->cur_msg_p == ( cur->p + 12 ) )
{
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "swap epochs to send finished message" ) );
ssl_swap_epochs( ssl );
}
- memcpy( ssl->out_msg, cur->p, cur->len );
- ssl->out_msglen = cur->len;
- ssl->out_msgtype = cur->type;
+ ret = ssl_get_remaining_payload_in_datagram( ssl );
+ if( ret < 0 )
+ return( ret );
+ max_frag_len = (size_t) ret;
- ssl->handshake->cur_msg = cur->next;
+ /* CCS is copied as is, while HS messages may need fragmentation */
+ if( cur->type == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
+ {
+ if( max_frag_len == 0 )
+ {
+ if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
+ return( ret );
- MBEDTLS_SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 );
+ continue;
+ }
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ memcpy( ssl->out_msg, cur->p, cur->len );
+ ssl->out_msglen = cur->len;
+ ssl->out_msgtype = cur->type;
+
+ /* Update position inside current message */
+ ssl->handshake->cur_msg_p += cur->len;
+ }
+ else
+ {
+ const unsigned char * const p = ssl->handshake->cur_msg_p;
+ const size_t hs_len = cur->len - 12;
+ const size_t frag_off = p - ( cur->p + 12 );
+ const size_t rem_len = hs_len - frag_off;
+ size_t cur_hs_frag_len, max_hs_frag_len;
+
+ if( ( max_frag_len < 12 ) || ( max_frag_len == 12 && hs_len != 0 ) )
+ {
+ if( is_finished )
+ ssl_swap_epochs( ssl );
+
+ if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
+ return( ret );
+
+ continue;
+ }
+ max_hs_frag_len = max_frag_len - 12;
+
+ cur_hs_frag_len = rem_len > max_hs_frag_len ?
+ max_hs_frag_len : rem_len;
+
+ if( frag_off == 0 && cur_hs_frag_len != hs_len )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "fragmenting handshake message (%u > %u)",
+ (unsigned) cur_hs_frag_len,
+ (unsigned) max_hs_frag_len ) );
+ }
+
+ /* Messages are stored with handshake headers as if not fragmented,
+ * copy beginning of headers then fill fragmentation fields.
+ * Handshake headers: type(1) len(3) seq(2) f_off(3) f_len(3) */
+ memcpy( ssl->out_msg, cur->p, 6 );
+
+ ssl->out_msg[6] = ( ( frag_off >> 16 ) & 0xff );
+ ssl->out_msg[7] = ( ( frag_off >> 8 ) & 0xff );
+ ssl->out_msg[8] = ( ( frag_off ) & 0xff );
+
+ ssl->out_msg[ 9] = ( ( cur_hs_frag_len >> 16 ) & 0xff );
+ ssl->out_msg[10] = ( ( cur_hs_frag_len >> 8 ) & 0xff );
+ ssl->out_msg[11] = ( ( cur_hs_frag_len ) & 0xff );
+
+ MBEDTLS_SSL_DEBUG_BUF( 3, "handshake header", ssl->out_msg, 12 );
+
+ /* Copy the handshake message content and set records fields */
+ memcpy( ssl->out_msg + 12, p, cur_hs_frag_len );
+ ssl->out_msglen = cur_hs_frag_len + 12;
+ ssl->out_msgtype = cur->type;
+
+ /* Update position inside current message */
+ ssl->handshake->cur_msg_p += cur_hs_frag_len;
+ }
+
+ /* If done with the current message move to the next one if any */
+ if( ssl->handshake->cur_msg_p >= cur->p + cur->len )
+ {
+ if( cur->next != NULL )
+ {
+ ssl->handshake->cur_msg = cur->next;
+ ssl->handshake->cur_msg_p = cur->next->p + 12;
+ }
+ else
+ {
+ ssl->handshake->cur_msg = NULL;
+ ssl->handshake->cur_msg_p = NULL;
+ }
+ }
+
+ /* Actually send the message out */
+ if( ( ret = mbedtls_ssl_write_record( ssl, force_flush ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
return( ret );
}
}
+ if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
+ return( ret );
+
+ /* Update state and set timer */
if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER )
ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED;
else
@@ -2878,7 +3091,7 @@
ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
}
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_flight_transmit" ) );
return( 0 );
}
@@ -2896,6 +3109,12 @@
/* The next incoming flight will start with this msg_seq */
ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq;
+ /* We don't want to remember CCS's across flight boundaries. */
+ ssl->handshake->buffering.seen_ccs = 0;
+
+ /* Clear future message buffering structure. */
+ ssl_buffering_free( ssl );
+
/* Cancel timer */
ssl_set_timer( ssl, 0 );
@@ -2927,43 +3146,100 @@
#endif /* MBEDTLS_SSL_PROTO_DTLS */
/*
- * Record layer functions
+ * Handshake layer functions
*/
/*
- * Write current record.
- * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg.
+ * Write (DTLS: or queue) current handshake (including CCS) message.
+ *
+ * - fill in handshake headers
+ * - update handshake checksum
+ * - DTLS: save message for resending
+ * - then pass to the record layer
+ *
+ * DTLS: except for HelloRequest, messages are only queued, and will only be
+ * actually sent when calling flight_transmit() or resend().
+ *
+ * Inputs:
+ * - ssl->out_msglen: 4 + actual handshake message len
+ * (4 is the size of handshake headers for TLS)
+ * - ssl->out_msg[0]: the handshake type (ClientHello, ServerHello, etc)
+ * - ssl->out_msg + 4: the handshake message body
+ *
+ * Outputs, ie state before passing to flight_append() or write_record():
+ * - ssl->out_msglen: the length of the record contents
+ * (including handshake headers but excluding record headers)
+ * - ssl->out_msg: the record contents (handshake headers + content)
*/
-int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl )
+int mbedtls_ssl_write_handshake_msg( mbedtls_ssl_context *ssl )
{
- int ret, done = 0, out_msg_type;
- size_t len = ssl->out_msglen;
+ int ret;
+ const size_t hs_len = ssl->out_msglen - 4;
+ const unsigned char hs_type = ssl->out_msg[0];
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write handshake message" ) );
+
+ /*
+ * Sanity checks
+ */
+ if( ssl->out_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE &&
+ ssl->out_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
+ {
+ /* In SSLv3, the client might send a NoCertificate alert. */
+#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C)
+ if( ! ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 &&
+ ssl->out_msgtype == MBEDTLS_SSL_MSG_ALERT &&
+ ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) )
+#endif /* MBEDTLS_SSL_PROTO_SSL3 && MBEDTLS_SSL_SRV_C */
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+ }
+
+ if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
+ hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST &&
+ ssl->handshake == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL &&
ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
{
- ; /* Skip special handshake treatment when resending */
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
}
- else
#endif
+
+ /* Double-check that we did not exceed the bounds
+ * of the outgoing record buffer.
+ * This should never fail as the various message
+ * writing functions must obey the bounds of the
+ * outgoing record buffer, but better be safe.
+ *
+ * Note: We deliberately do not check for the MTU or MFL here.
+ */
+ if( ssl->out_msglen > MBEDTLS_SSL_OUT_CONTENT_LEN )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Record too large: "
+ "size %u, maximum %u",
+ (unsigned) ssl->out_msglen,
+ (unsigned) MBEDTLS_SSL_OUT_CONTENT_LEN ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ /*
+ * Fill handshake headers
+ */
if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE )
{
- out_msg_type = ssl->out_msg[0];
-
- if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST &&
- ssl->handshake == NULL )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
- return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
- }
-
- ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 );
- ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 );
- ssl->out_msg[3] = (unsigned char)( ( len - 4 ) );
+ ssl->out_msg[1] = (unsigned char)( hs_len >> 16 );
+ ssl->out_msg[2] = (unsigned char)( hs_len >> 8 );
+ ssl->out_msg[3] = (unsigned char)( hs_len );
/*
* DTLS has additional fields in the Handshake layer,
@@ -2980,17 +3256,16 @@
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS handshake message too large: "
"size %u, maximum %u",
- (unsigned) ( ssl->in_hslen - 4 ),
+ (unsigned) ( hs_len ),
(unsigned) ( MBEDTLS_SSL_OUT_CONTENT_LEN - 12 ) ) );
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
}
- memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 );
+ memmove( ssl->out_msg + 12, ssl->out_msg + 4, hs_len );
ssl->out_msglen += 8;
- len += 8;
/* Write message_seq and update it, except for HelloRequest */
- if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
+ if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
{
ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF;
ssl->out_msg[5] = ( ssl->handshake->out_msg_seq ) & 0xFF;
@@ -3002,23 +3277,23 @@
ssl->out_msg[5] = 0;
}
- /* We don't fragment, so frag_offset = 0 and frag_len = len */
+ /* Handshake hashes are computed without fragmentation,
+ * so set frag_offset = 0 and frag_len = hs_len for now */
memset( ssl->out_msg + 6, 0x00, 3 );
memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 );
}
#endif /* MBEDTLS_SSL_PROTO_DTLS */
- if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
- ssl->handshake->update_checksum( ssl, ssl->out_msg, len );
+ /* Update running hashes of handshake messages seen */
+ if( hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST )
+ ssl->handshake->update_checksum( ssl, ssl->out_msg, ssl->out_msglen );
}
- /* Save handshake and CCS messages for resending */
+ /* Either send now, or just save to be sent (and resent) later */
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
- ssl->handshake != NULL &&
- ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING &&
- ( ssl->out_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ||
- ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) )
+ ( ssl->out_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ||
+ hs_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) )
{
if( ( ret = ssl_flight_append( ssl ) ) != 0 )
{
@@ -3026,7 +3301,40 @@
return( ret );
}
}
+ else
#endif
+ {
+ if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "ssl_write_record", ret );
+ return( ret );
+ }
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write handshake message" ) );
+
+ return( 0 );
+}
+
+/*
+ * Record layer functions
+ */
+
+/*
+ * Write current record.
+ *
+ * Uses:
+ * - ssl->out_msgtype: type of the message (AppData, Handshake, Alert, CCS)
+ * - ssl->out_msglen: length of the record content (excl headers)
+ * - ssl->out_msg: record content
+ */
+int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl, uint8_t force_flush )
+{
+ int ret, done = 0;
+ size_t len = ssl->out_msglen;
+ uint8_t flush = force_flush;
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) );
#if defined(MBEDTLS_ZLIB_SUPPORT)
if( ssl->transform_out != NULL &&
@@ -3060,10 +3368,14 @@
#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */
if( !done )
{
+ unsigned i;
+ size_t protected_record_size;
+
ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype;
mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver,
ssl->conf->transport, ssl->out_hdr + 1 );
+ memcpy( ssl->out_ctr, ssl->cur_out_ctr, 8 );
ssl->out_len[0] = (unsigned char)( len >> 8 );
ssl->out_len[1] = (unsigned char)( len );
@@ -3080,18 +3392,76 @@
ssl->out_len[1] = (unsigned char)( len );
}
- ssl->out_left = mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen;
+ protected_record_size = len + mbedtls_ssl_hdr_len( ssl );
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ /* In case of DTLS, double-check that we don't exceed
+ * the remaining space in the datagram. */
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ {
+ ret = ssl_get_remaining_space_in_datagram( ssl );
+ if( ret < 0 )
+ return( ret );
+
+ if( protected_record_size > (size_t) ret )
+ {
+ /* Should never happen */
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, "
- "version = [%d:%d], msglen = %d",
- ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2],
- ( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) );
+ "version = [%d:%d], msglen = %d",
+ ssl->out_hdr[0], ssl->out_hdr[1],
+ ssl->out_hdr[2], len ) );
MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network",
- ssl->out_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen );
+ ssl->out_hdr, protected_record_size );
+
+ ssl->out_left += protected_record_size;
+ ssl->out_hdr += protected_record_size;
+ ssl_update_out_pointers( ssl, ssl->transform_out );
+
+ for( i = 8; i > ssl_ep_len( ssl ); i-- )
+ if( ++ssl->cur_out_ctr[i - 1] != 0 )
+ break;
+
+ /* The loop goes to its end iff the counter is wrapping */
+ if( i == ssl_ep_len( ssl ) )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) );
+ return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING );
+ }
}
- if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ flush == SSL_DONT_FORCE_FLUSH )
+ {
+ size_t remaining;
+ ret = ssl_get_remaining_payload_in_datagram( ssl );
+ if( ret < 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_remaining_payload_in_datagram",
+ ret );
+ return( ret );
+ }
+
+ remaining = (size_t) ret;
+ if( remaining == 0 )
+ {
+ flush = SSL_FORCE_FLUSH;
+ }
+ else
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Still %u bytes available in current datagram", (unsigned) remaining ) );
+ }
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+ if( ( flush == SSL_FORCE_FLUSH ) &&
+ ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret );
return( ret );
@@ -3103,6 +3473,52 @@
}
#if defined(MBEDTLS_SSL_PROTO_DTLS)
+
+static int ssl_hs_is_proper_fragment( mbedtls_ssl_context *ssl )
+{
+ if( ssl->in_msglen < ssl->in_hslen ||
+ memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 ||
+ memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 )
+ {
+ return( 1 );
+ }
+ return( 0 );
+}
+
+static uint32_t ssl_get_hs_frag_len( mbedtls_ssl_context const *ssl )
+{
+ return( ( ssl->in_msg[9] << 16 ) |
+ ( ssl->in_msg[10] << 8 ) |
+ ssl->in_msg[11] );
+}
+
+static uint32_t ssl_get_hs_frag_off( mbedtls_ssl_context const *ssl )
+{
+ return( ( ssl->in_msg[6] << 16 ) |
+ ( ssl->in_msg[7] << 8 ) |
+ ssl->in_msg[8] );
+}
+
+static int ssl_check_hs_header( mbedtls_ssl_context const *ssl )
+{
+ uint32_t msg_len, frag_off, frag_len;
+
+ msg_len = ssl_get_hs_total_len( ssl );
+ frag_off = ssl_get_hs_frag_off( ssl );
+ frag_len = ssl_get_hs_frag_len( ssl );
+
+ if( frag_off > msg_len )
+ return( -1 );
+
+ if( frag_len > msg_len - frag_off )
+ return( -1 );
+
+ if( frag_len + 12 > ssl->in_msglen )
+ return( -1 );
+
+ return( 0 );
+}
+
/*
* Mark bits in bitmask (used for DTLS HS reassembly)
*/
@@ -3164,162 +3580,30 @@
return( 0 );
}
-/*
- * Reassemble fragmented DTLS handshake messages.
- *
- * Use a temporary buffer for reassembly, divided in two parts:
- * - the first holds the reassembled message (including handshake header),
- * - the second holds a bitmask indicating which parts of the message
- * (excluding headers) have been received so far.
- */
-static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl )
+/* msg_len does not include the handshake header */
+static size_t ssl_get_reassembly_buffer_size( size_t msg_len,
+ unsigned add_bitmap )
{
- unsigned char *msg, *bitmask;
- size_t frag_len, frag_off;
- size_t msg_len = ssl->in_hslen - 12; /* Without headers */
+ size_t alloc_len;
- if( ssl->handshake == NULL )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) );
- return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
- }
+ alloc_len = 12; /* Handshake header */
+ alloc_len += msg_len; /* Content buffer */
- /*
- * For first fragment, check size and allocate buffer
- */
- if( ssl->handshake->hs_msg == NULL )
- {
- size_t alloc_len;
+ if( add_bitmap )
+ alloc_len += msg_len / 8 + ( msg_len % 8 != 0 ); /* Bitmap */
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d",
- msg_len ) );
-
- if( ssl->in_hslen > MBEDTLS_SSL_IN_CONTENT_LEN )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too large" ) );
- return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
- }
-
- /* The bitmask needs one bit per byte of message excluding header */
- alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 );
-
- ssl->handshake->hs_msg = mbedtls_calloc( 1, alloc_len );
- if( ssl->handshake->hs_msg == NULL )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", alloc_len ) );
- return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
- }
-
- /* Prepare final header: copy msg_type, length and message_seq,
- * then add standardised fragment_offset and fragment_length */
- memcpy( ssl->handshake->hs_msg, ssl->in_msg, 6 );
- memset( ssl->handshake->hs_msg + 6, 0, 3 );
- memcpy( ssl->handshake->hs_msg + 9,
- ssl->handshake->hs_msg + 1, 3 );
- }
- else
- {
- /* Make sure msg_type and length are consistent */
- if( memcmp( ssl->handshake->hs_msg, ssl->in_msg, 4 ) != 0 )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment header mismatch" ) );
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
- }
- }
-
- msg = ssl->handshake->hs_msg + 12;
- bitmask = msg + msg_len;
-
- /*
- * Check and copy current fragment
- */
- frag_off = ( ssl->in_msg[6] << 16 ) |
- ( ssl->in_msg[7] << 8 ) |
- ssl->in_msg[8];
- frag_len = ( ssl->in_msg[9] << 16 ) |
- ( ssl->in_msg[10] << 8 ) |
- ssl->in_msg[11];
-
- if( frag_off + frag_len > msg_len )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment offset/len: %d + %d > %d",
- frag_off, frag_len, msg_len ) );
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
- }
-
- if( frag_len + 12 > ssl->in_msglen )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment length: %d + 12 > %d",
- frag_len, ssl->in_msglen ) );
- return( MBEDTLS_ERR_SSL_INVALID_RECORD );
- }
-
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d",
- frag_off, frag_len ) );
-
- memcpy( msg + frag_off, ssl->in_msg + 12, frag_len );
- ssl_bitmask_set( bitmask, frag_off, frag_len );
-
- /*
- * Do we have the complete message by now?
- * If yes, finalize it, else ask to read the next record.
- */
- if( ssl_bitmask_check( bitmask, msg_len ) != 0 )
- {
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "message is not complete yet" ) );
- return( MBEDTLS_ERR_SSL_CONTINUE_PROCESSING );
- }
-
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake message completed" ) );
-
- if( frag_len + 12 < ssl->in_msglen )
- {
- /*
- * We'got more handshake messages in the same record.
- * This case is not handled now because no know implementation does
- * that and it's hard to test, so we prefer to fail cleanly for now.
- */
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "last fragment not alone in its record" ) );
- return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
- }
-
- if( ssl->in_left > ssl->next_record_offset )
- {
- /*
- * We've got more data in the buffer after the current record,
- * that we don't want to overwrite. Move it before writing the
- * reassembled message, and adjust in_left and next_record_offset.
- */
- unsigned char *cur_remain = ssl->in_hdr + ssl->next_record_offset;
- unsigned char *new_remain = ssl->in_msg + ssl->in_hslen;
- size_t remain_len = ssl->in_left - ssl->next_record_offset;
-
- /* First compute and check new lengths */
- ssl->next_record_offset = new_remain - ssl->in_hdr;
- ssl->in_left = ssl->next_record_offset + remain_len;
-
- if( ssl->in_left > MBEDTLS_SSL_IN_BUFFER_LEN -
- (size_t)( ssl->in_hdr - ssl->in_buf ) )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "reassembled message too large for buffer" ) );
- return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
- }
-
- memmove( new_remain, cur_remain, remain_len );
- }
-
- memcpy( ssl->in_msg, ssl->handshake->hs_msg, ssl->in_hslen );
-
- mbedtls_free( ssl->handshake->hs_msg );
- ssl->handshake->hs_msg = NULL;
-
- MBEDTLS_SSL_DEBUG_BUF( 3, "reassembled handshake message",
- ssl->in_msg, ssl->in_hslen );
-
- return( 0 );
+ return( alloc_len );
}
+
#endif /* MBEDTLS_SSL_PROTO_DTLS */
+static uint32_t ssl_get_hs_total_len( mbedtls_ssl_context const *ssl )
+{
+ return( ( ssl->in_msg[1] << 16 ) |
+ ( ssl->in_msg[2] << 8 ) |
+ ssl->in_msg[3] );
+}
+
int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl )
{
if( ssl->in_msglen < mbedtls_ssl_hs_hdr_len( ssl ) )
@@ -3329,10 +3613,7 @@
return( MBEDTLS_ERR_SSL_INVALID_RECORD );
}
- ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + (
- ( ssl->in_msg[1] << 16 ) |
- ( ssl->in_msg[2] << 8 ) |
- ssl->in_msg[3] );
+ ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + ssl_get_hs_total_len( ssl );
MBEDTLS_SSL_DEBUG_MSG( 3, ( "handshake message: msglen ="
" %d, type = %d, hslen = %d",
@@ -3344,12 +3625,26 @@
int ret;
unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
+ if( ssl_check_hs_header( ssl ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid handshake header" ) );
+ return( MBEDTLS_ERR_SSL_INVALID_RECORD );
+ }
+
if( ssl->handshake != NULL &&
( ( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER &&
recv_msg_seq != ssl->handshake->in_msg_seq ) ||
( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER &&
ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) ) )
{
+ if( recv_msg_seq > ssl->handshake->in_msg_seq )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "received future handshake message of sequence number %u (next %u)",
+ recv_msg_seq,
+ ssl->handshake->in_msg_seq ) );
+ return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
+ }
+
/* Retransmit only on last message from previous flight, to avoid
* too many retransmissions.
* Besides, No sane server ever retransmits HelloVerifyRequest */
@@ -3379,20 +3674,14 @@
}
/* Wait until message completion to increment in_msg_seq */
- /* Reassemble if current message is fragmented or reassembly is
- * already in progress */
- if( ssl->in_msglen < ssl->in_hslen ||
- memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 ||
- memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 ||
- ( ssl->handshake != NULL && ssl->handshake->hs_msg != NULL ) )
+ /* Message reassembly is handled alongside buffering of future
+ * messages; the commonality is that both handshake fragments and
+ * future messages cannot be forwarded immediately to the
+ * handshake logic layer. */
+ if( ssl_hs_is_proper_fragment( ssl ) == 1 )
{
MBEDTLS_SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) );
-
- if( ( ret = ssl_reassemble_dtls_handshake( ssl ) ) != 0 )
- {
- MBEDTLS_SSL_DEBUG_RET( 1, "ssl_reassemble_dtls_handshake", ret );
- return( ret );
- }
+ return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
}
}
else
@@ -3409,9 +3698,9 @@
void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl )
{
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
- if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER &&
- ssl->handshake != NULL )
+ if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && hs != NULL )
{
ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen );
}
@@ -3421,7 +3710,29 @@
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ssl->handshake != NULL )
{
- ssl->handshake->in_msg_seq++;
+ unsigned offset;
+ mbedtls_ssl_hs_buffer *hs_buf;
+
+ /* Increment handshake sequence number */
+ hs->in_msg_seq++;
+
+ /*
+ * Clear up handshake buffering and reassembly structure.
+ */
+
+ /* Free first entry */
+ ssl_buffering_free_slot( ssl, 0 );
+
+ /* Shift all other entries */
+ for( offset = 0, hs_buf = &hs->buffering.hs[0];
+ offset + 1 < MBEDTLS_SSL_MAX_BUFFERED_HS;
+ offset++, hs_buf++ )
+ {
+ *hs_buf = *(hs_buf + 1);
+ }
+
+ /* Create a fresh last entry */
+ memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) );
}
#endif
}
@@ -3822,7 +4133,16 @@
}
else
#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
+ {
+ /* Consider buffering the record. */
+ if( rec_epoch == (unsigned int) ssl->in_epoch + 1 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Consider record for buffering" ) );
+ return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
+ }
+
return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
+ }
}
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY)
@@ -3835,15 +4155,6 @@
}
#endif
- /* Drop unexpected ChangeCipherSpec messages */
- if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC &&
- ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC &&
- ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) );
- return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
- }
-
/* Drop unexpected ApplicationData records,
* except at the beginning of renegotiations */
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA &&
@@ -3980,7 +4291,14 @@
* RFC 6347 4.1.2.7) and continue reading until a valid record is found.
*
*/
-int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl )
+
+/* Helper functions for mbedtls_ssl_read_record(). */
+static int ssl_consume_current_message( mbedtls_ssl_context *ssl );
+static int ssl_get_next_record( mbedtls_ssl_context *ssl );
+static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl );
+
+int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl,
+ unsigned update_hs_digest )
{
int ret;
@@ -3990,17 +4308,53 @@
{
do {
- do ret = mbedtls_ssl_read_record_layer( ssl );
- while( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING );
-
+ ret = ssl_consume_current_message( ssl );
if( ret != 0 )
- {
- MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret );
return( ret );
+
+ if( ssl_record_is_in_progress( ssl ) == 0 )
+ {
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ int have_buffered = 0;
+
+ /* We only check for buffered messages if the
+ * current datagram is fully consumed. */
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ ssl_next_record_is_in_datagram( ssl ) == 0 )
+ {
+ if( ssl_load_buffered_message( ssl ) == 0 )
+ have_buffered = 1;
+ }
+
+ if( have_buffered == 0 )
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+ {
+ ret = ssl_get_next_record( ssl );
+ if( ret == MBEDTLS_ERR_SSL_CONTINUE_PROCESSING )
+ continue;
+
+ if( ret != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_get_next_record" ), ret );
+ return( ret );
+ }
+ }
}
ret = mbedtls_ssl_handle_message_type( ssl );
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE )
+ {
+ /* Buffer future message */
+ ret = ssl_buffer_message( ssl );
+ if( ret != 0 )
+ return( ret );
+
+ ret = MBEDTLS_ERR_SSL_CONTINUE_PROCESSING;
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
} while( MBEDTLS_ERR_SSL_NON_FATAL == ret ||
MBEDTLS_ERR_SSL_CONTINUE_PROCESSING == ret );
@@ -4010,14 +4364,15 @@
return( ret );
}
- if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE )
+ if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE &&
+ update_hs_digest == 1 )
{
mbedtls_ssl_update_handshake_status( ssl );
}
}
else
{
- MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= reuse previously read message" ) );
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "reuse previously read message" ) );
ssl->keep_current_message = 0;
}
@@ -4026,13 +4381,350 @@
return( 0 );
}
-int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl )
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+static int ssl_next_record_is_in_datagram( mbedtls_ssl_context *ssl )
{
- int ret;
+ if( ssl->in_left > ssl->next_record_offset )
+ return( 1 );
+ return( 0 );
+}
+
+static int ssl_load_buffered_message( mbedtls_ssl_context *ssl )
+{
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+ mbedtls_ssl_hs_buffer * hs_buf;
+ int ret = 0;
+
+ if( hs == NULL )
+ return( -1 );
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_messsage" ) );
+
+ if( ssl->state == MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC ||
+ ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
+ {
+ /* Check if we have seen a ChangeCipherSpec before.
+ * If yes, synthesize a CCS record. */
+ if( !hs->buffering.seen_ccs )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "CCS not seen in the current flight" ) );
+ ret = -1;
+ goto exit;
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Injecting buffered CCS message" ) );
+ ssl->in_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC;
+ ssl->in_msglen = 1;
+ ssl->in_msg[0] = 1;
+
+ /* As long as they are equal, the exact value doesn't matter. */
+ ssl->in_left = 0;
+ ssl->next_record_offset = 0;
+
+ hs->buffering.seen_ccs = 0;
+ goto exit;
+ }
+
+#if defined(MBEDTLS_DEBUG_C)
+ /* Debug only */
+ {
+ unsigned offset;
+ for( offset = 1; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ )
+ {
+ hs_buf = &hs->buffering.hs[offset];
+ if( hs_buf->is_valid == 1 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Future message with sequence number %u %s buffered.",
+ hs->in_msg_seq + offset,
+ hs_buf->is_complete ? "fully" : "partially" ) );
+ }
+ }
+ }
+#endif /* MBEDTLS_DEBUG_C */
+
+ /* Check if we have buffered and/or fully reassembled the
+ * next handshake message. */
+ hs_buf = &hs->buffering.hs[0];
+ if( ( hs_buf->is_valid == 1 ) && ( hs_buf->is_complete == 1 ) )
+ {
+ /* Synthesize a record containing the buffered HS message. */
+ size_t msg_len = ( hs_buf->data[1] << 16 ) |
+ ( hs_buf->data[2] << 8 ) |
+ hs_buf->data[3];
+
+ /* 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 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message has been buffered - load" ) );
+ MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered handshake message (incl. header)",
+ hs_buf->data, msg_len + 12 );
+
+ ssl->in_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
+ ssl->in_hslen = msg_len + 12;
+ ssl->in_msglen = msg_len + 12;
+ memcpy( ssl->in_msg, hs_buf->data, ssl->in_hslen );
+
+ ret = 0;
+ goto exit;
+ }
+ else
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Next handshake message %u not or only partially bufffered",
+ hs->in_msg_seq ) );
+ }
+
+ ret = -1;
+
+exit:
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_message" ) );
+ return( ret );
+}
+
+static int ssl_buffer_make_space( mbedtls_ssl_context *ssl,
+ size_t desired )
+{
+ int offset;
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Attempt to free buffered messages to have %u bytes available",
+ (unsigned) desired ) );
+
+ /* Get rid of future records epoch first, if such exist. */
+ ssl_free_buffered_record( ssl );
+
+ /* Check if we have enough space available now. */
+ if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
+ hs->buffering.total_bytes_buffered ) )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing future epoch record" ) );
+ return( 0 );
+ }
+
+ /* We don't have enough space to buffer the next expected handshake
+ * message. Remove buffers used for future messages to gain space,
+ * starting with the most distant one. */
+ for( offset = MBEDTLS_SSL_MAX_BUFFERED_HS - 1;
+ offset >= 0; offset-- )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Free buffering slot %d to make space for reassembly of next handshake message",
+ offset ) );
+
+ ssl_buffering_free_slot( ssl, (uint8_t) offset );
+
+ /* Check if we have enough space available now. */
+ if( desired <= ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
+ hs->buffering.total_bytes_buffered ) )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Enough space available after freeing buffered HS messages" ) );
+ return( 0 );
+ }
+ }
+
+ return( -1 );
+}
+
+static int ssl_buffer_message( mbedtls_ssl_context *ssl )
+{
+ int ret = 0;
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+
+ if( hs == NULL )
+ return( 0 );
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_buffer_message" ) );
+
+ switch( ssl->in_msgtype )
+ {
+ case MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC:
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Remember CCS message" ) );
+
+ hs->buffering.seen_ccs = 1;
+ break;
+
+ case MBEDTLS_SSL_MSG_HANDSHAKE:
+ {
+ unsigned recv_msg_seq_offset;
+ unsigned recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5];
+ mbedtls_ssl_hs_buffer *hs_buf;
+ size_t msg_len = ssl->in_hslen - 12;
+
+ /* We should never receive an old handshake
+ * message - double-check nonetheless. */
+ if( recv_msg_seq < ssl->handshake->in_msg_seq )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ recv_msg_seq_offset = recv_msg_seq - ssl->handshake->in_msg_seq;
+ if( recv_msg_seq_offset >= MBEDTLS_SSL_MAX_BUFFERED_HS )
+ {
+ /* Silently ignore -- message too far in the future */
+ MBEDTLS_SSL_DEBUG_MSG( 2,
+ ( "Ignore future HS message with sequence number %u, "
+ "buffering window %u - %u",
+ recv_msg_seq, ssl->handshake->in_msg_seq,
+ ssl->handshake->in_msg_seq + MBEDTLS_SSL_MAX_BUFFERED_HS - 1 ) );
+
+ goto exit;
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering HS message with sequence number %u, offset %u ",
+ recv_msg_seq, recv_msg_seq_offset ) );
+
+ hs_buf = &hs->buffering.hs[ recv_msg_seq_offset ];
+
+ /* Check if the buffering for this seq nr has already commenced. */
+ if( !hs_buf->is_valid )
+ {
+ size_t reassembly_buf_sz;
+
+ hs_buf->is_fragmented =
+ ( ssl_hs_is_proper_fragment( ssl ) == 1 );
+
+ /* We copy the message back into the input buffer
+ * after reassembly, so check that it's not too large.
+ * 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 )
+ {
+ /* Ignore message */
+ goto exit;
+ }
+
+ /* Check if we have enough space to buffer the message. */
+ if( hs->buffering.total_bytes_buffered >
+ MBEDTLS_SSL_DTLS_MAX_BUFFERING )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ reassembly_buf_sz = ssl_get_reassembly_buffer_size( msg_len,
+ hs_buf->is_fragmented );
+
+ if( reassembly_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
+ hs->buffering.total_bytes_buffered ) )
+ {
+ if( recv_msg_seq_offset > 0 )
+ {
+ /* If we can't buffer a future message because
+ * of space limitations -- ignore. */
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n",
+ (unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING,
+ (unsigned) hs->buffering.total_bytes_buffered ) );
+ goto exit;
+ }
+ else
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future message of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- attempt to make space by freeing buffered future messages\n",
+ (unsigned) msg_len, MBEDTLS_SSL_DTLS_MAX_BUFFERING,
+ (unsigned) hs->buffering.total_bytes_buffered ) );
+ }
+
+ if( ssl_buffer_make_space( ssl, reassembly_buf_sz ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Reassembly of next message of size %u (%u with bitmap) would exceed the compile-time limit %u (already %u bytes buffered) -- fail\n",
+ (unsigned) msg_len,
+ (unsigned) reassembly_buf_sz,
+ MBEDTLS_SSL_DTLS_MAX_BUFFERING,
+ (unsigned) hs->buffering.total_bytes_buffered ) );
+ ret = MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL;
+ goto exit;
+ }
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d",
+ msg_len ) );
+
+ hs_buf->data = mbedtls_calloc( 1, reassembly_buf_sz );
+ if( hs_buf->data == NULL )
+ {
+ ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ goto exit;
+ }
+ hs_buf->data_len = reassembly_buf_sz;
+
+ /* Prepare final header: copy msg_type, length and message_seq,
+ * then add standardised fragment_offset and fragment_length */
+ memcpy( hs_buf->data, ssl->in_msg, 6 );
+ memset( hs_buf->data + 6, 0, 3 );
+ memcpy( hs_buf->data + 9, hs_buf->data + 1, 3 );
+
+ hs_buf->is_valid = 1;
+
+ hs->buffering.total_bytes_buffered += reassembly_buf_sz;
+ }
+ else
+ {
+ /* Make sure msg_type and length are consistent */
+ if( memcmp( hs_buf->data, ssl->in_msg, 4 ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "Fragment header mismatch - ignore" ) );
+ /* Ignore */
+ goto exit;
+ }
+ }
+
+ if( !hs_buf->is_complete )
+ {
+ size_t frag_len, frag_off;
+ unsigned char * const msg = hs_buf->data + 12;
+
+ /*
+ * Check and copy current fragment
+ */
+
+ /* Validation of header fields already done in
+ * mbedtls_ssl_prepare_handshake_record(). */
+ frag_off = ssl_get_hs_frag_off( ssl );
+ frag_len = ssl_get_hs_frag_len( ssl );
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d",
+ frag_off, frag_len ) );
+ memcpy( msg + frag_off, ssl->in_msg + 12, frag_len );
+
+ if( hs_buf->is_fragmented )
+ {
+ unsigned char * const bitmask = msg + msg_len;
+ ssl_bitmask_set( bitmask, frag_off, frag_len );
+ hs_buf->is_complete = ( ssl_bitmask_check( bitmask,
+ msg_len ) == 0 );
+ }
+ else
+ {
+ hs_buf->is_complete = 1;
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "message %scomplete",
+ hs_buf->is_complete ? "" : "not yet " ) );
+ }
+
+ break;
+ }
+
+ default:
+ /* We don't buffer other types of messages. */
+ break;
+ }
+
+exit:
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_buffer_message" ) );
+ return( ret );
+}
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+static int ssl_consume_current_message( mbedtls_ssl_context *ssl )
+{
/*
- * Step A
- *
* Consume last content-layer message and potentially
* update in_msglen which keeps track of the contents'
* consumption state.
@@ -4114,20 +4806,161 @@
ssl->in_msglen = 0;
}
- /*
- * Step B
- *
- * Fetch and decode new record if current one is fully consumed.
- *
- */
+ return( 0 );
+}
+static int ssl_record_is_in_progress( mbedtls_ssl_context *ssl )
+{
if( ssl->in_msglen > 0 )
+ return( 1 );
+
+ return( 0 );
+}
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+
+static void ssl_free_buffered_record( mbedtls_ssl_context *ssl )
+{
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+ if( hs == NULL )
+ return;
+
+ if( hs->buffering.future_record.data != NULL )
{
- /* There's something left to be processed in the current record. */
+ hs->buffering.total_bytes_buffered -=
+ hs->buffering.future_record.len;
+
+ mbedtls_free( hs->buffering.future_record.data );
+ hs->buffering.future_record.data = NULL;
+ }
+}
+
+static int ssl_load_buffered_record( mbedtls_ssl_context *ssl )
+{
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+ unsigned char * rec;
+ size_t rec_len;
+ unsigned rec_epoch;
+
+ if( ssl->conf->transport != MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ return( 0 );
+
+ if( hs == NULL )
+ return( 0 );
+
+ rec = hs->buffering.future_record.data;
+ rec_len = hs->buffering.future_record.len;
+ rec_epoch = hs->buffering.future_record.epoch;
+
+ if( rec == NULL )
+ return( 0 );
+
+ /* Only consider loading future records if the
+ * input buffer is empty. */
+ if( ssl_next_record_is_in_datagram( ssl ) == 1 )
+ return( 0 );
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> ssl_load_buffered_record" ) );
+
+ if( rec_epoch != ssl->in_epoch )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffered record not from current epoch." ) );
+ goto exit;
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Found buffered record from current epoch - load" ) );
+
+ /* Double-check that the record is not too large */
+ if( rec_len > MBEDTLS_SSL_IN_BUFFER_LEN -
+ (size_t)( ssl->in_hdr - ssl->in_buf ) )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) );
+ return( MBEDTLS_ERR_SSL_INTERNAL_ERROR );
+ }
+
+ memcpy( ssl->in_hdr, rec, rec_len );
+ ssl->in_left = rec_len;
+ ssl->next_record_offset = 0;
+
+ ssl_free_buffered_record( ssl );
+
+exit:
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= ssl_load_buffered_record" ) );
+ return( 0 );
+}
+
+static int ssl_buffer_future_record( mbedtls_ssl_context *ssl )
+{
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+ size_t const rec_hdr_len = 13;
+ size_t const total_buf_sz = rec_hdr_len + ssl->in_msglen;
+
+ /* Don't buffer future records outside handshakes. */
+ if( hs == NULL )
+ return( 0 );
+
+ /* Only buffer handshake records (we are only interested
+ * in Finished messages). */
+ if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE )
+ return( 0 );
+
+ /* Don't buffer more than one future epoch record. */
+ if( hs->buffering.future_record.data != NULL )
+ return( 0 );
+
+ /* Don't buffer record if there's not enough buffering space remaining. */
+ if( total_buf_sz > ( MBEDTLS_SSL_DTLS_MAX_BUFFERING -
+ hs->buffering.total_bytes_buffered ) )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffering of future epoch record of size %u would exceed the compile-time limit %u (already %u bytes buffered) -- ignore\n",
+ (unsigned) total_buf_sz, MBEDTLS_SSL_DTLS_MAX_BUFFERING,
+ (unsigned) hs->buffering.total_bytes_buffered ) );
return( 0 );
}
- /* Current record either fully processed or to be discarded. */
+ /* Buffer record */
+ MBEDTLS_SSL_DEBUG_MSG( 2, ( "Buffer record from epoch %u",
+ ssl->in_epoch + 1 ) );
+ MBEDTLS_SSL_DEBUG_BUF( 3, "Buffered record", ssl->in_hdr,
+ rec_hdr_len + ssl->in_msglen );
+
+ /* ssl_parse_record_header() only considers records
+ * of the next epoch as candidates for buffering. */
+ hs->buffering.future_record.epoch = ssl->in_epoch + 1;
+ hs->buffering.future_record.len = total_buf_sz;
+
+ hs->buffering.future_record.data =
+ mbedtls_calloc( 1, hs->buffering.future_record.len );
+ if( hs->buffering.future_record.data == NULL )
+ {
+ /* If we run out of RAM trying to buffer a
+ * record from the next epoch, just ignore. */
+ return( 0 );
+ }
+
+ memcpy( hs->buffering.future_record.data, ssl->in_hdr, total_buf_sz );
+
+ hs->buffering.total_bytes_buffered += total_buf_sz;
+ return( 0 );
+}
+
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+static int ssl_get_next_record( mbedtls_ssl_context *ssl )
+{
+ int ret;
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ /* We might have buffered a future record; if so,
+ * and if the epoch matches now, load it.
+ * On success, this call will set ssl->in_left to
+ * the length of the buffered record, so that
+ * the calls to ssl_fetch_input() below will
+ * essentially be no-ops. */
+ ret = ssl_load_buffered_record( ssl );
+ if( ret != 0 )
+ return( ret );
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) ) ) != 0 )
{
@@ -4141,6 +4974,16 @@
if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT )
{
+ if( ret == MBEDTLS_ERR_SSL_EARLY_MESSAGE )
+ {
+ ret = ssl_buffer_future_record( ssl );
+ if( ret != 0 )
+ return( ret );
+
+ /* Fall through to handling of unexpected records */
+ ret = MBEDTLS_ERR_SSL_UNEXPECTED_RECORD;
+ }
+
if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD )
{
/* Skip unexpected record (but not whole datagram) */
@@ -4272,6 +5115,39 @@
}
}
+ if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC )
+ {
+ if( ssl->in_msglen != 1 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, len: %d",
+ ssl->in_msglen ) );
+ return( MBEDTLS_ERR_SSL_INVALID_RECORD );
+ }
+
+ if( ssl->in_msg[0] != 1 )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid CCS message, content: %02x",
+ ssl->in_msg[0] ) );
+ return( MBEDTLS_ERR_SSL_INVALID_RECORD );
+ }
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC &&
+ ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC )
+ {
+ if( ssl->handshake == NULL )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping ChangeCipherSpec outside handshake" ) );
+ return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD );
+ }
+
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "received out-of-order ChangeCipherSpec - remember" ) );
+ return( MBEDTLS_ERR_SSL_EARLY_MESSAGE );
+ }
+#endif
+ }
+
if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT )
{
if( ssl->in_msglen != 2 )
@@ -4373,7 +5249,7 @@
ssl->out_msg[0] = level;
ssl->out_msg[1] = message;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
return( ret );
@@ -4542,9 +5418,9 @@
ssl->state++;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
@@ -4597,7 +5473,7 @@
}
#endif
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
/* mbedtls_ssl_read_record may have sent an alert already. We
let it decide whether to alert. */
@@ -4955,9 +5831,9 @@
ssl->state++;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
@@ -4972,7 +5848,7 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) );
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
@@ -4986,13 +5862,8 @@
return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE );
}
- if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 )
- {
- MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) );
- mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL,
- MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR );
- return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC );
- }
+ /* CCS records are only accepted if they have length 1 and content '1',
+ * so we don't need to check this here. */
/*
* Switch to our negotiated transform and session parameters for inbound
@@ -5022,16 +5893,7 @@
#endif /* MBEDTLS_SSL_PROTO_DTLS */
memset( ssl->in_ctr, 0, 8 );
- /*
- * Set the in_msg pointer to the correct location based on IV length
- */
- if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
- {
- ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen -
- ssl->transform_negotiate->fixed_ivlen;
- }
- else
- ssl->in_msg = ssl->in_iv;
+ ssl_update_in_pointers( ssl, ssl->transform_negotiate );
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_activate != NULL )
@@ -5482,16 +6344,7 @@
MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) );
- /*
- * Set the out_msg pointer to the correct location based on IV length
- */
- if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
- {
- ssl->out_msg = ssl->out_iv + ssl->transform_negotiate->ivlen -
- ssl->transform_negotiate->fixed_ivlen;
- }
- else
- ssl->out_msg = ssl->out_iv;
+ ssl_update_out_pointers( ssl, ssl->transform_negotiate );
ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->conf->endpoint );
@@ -5543,14 +6396,14 @@
/* Remember current epoch settings for resending */
ssl->handshake->alt_transform_out = ssl->transform_out;
- memcpy( ssl->handshake->alt_out_ctr, ssl->out_ctr, 8 );
+ memcpy( ssl->handshake->alt_out_ctr, ssl->cur_out_ctr, 8 );
/* Set sequence_number to zero */
- memset( ssl->out_ctr + 2, 0, 6 );
+ memset( ssl->cur_out_ctr + 2, 0, 6 );
/* Increment epoch */
for( i = 2; i > 0; i-- )
- if( ++ssl->out_ctr[i - 1] != 0 )
+ if( ++ssl->cur_out_ctr[i - 1] != 0 )
break;
/* The loop goes to its end iff the counter is wrapping */
@@ -5562,7 +6415,7 @@
}
else
#endif /* MBEDTLS_SSL_PROTO_DTLS */
- memset( ssl->out_ctr, 0, 8 );
+ memset( ssl->cur_out_ctr, 0, 8 );
ssl->transform_out = ssl->transform_negotiate;
ssl->session_out = ssl->session_negotiate;
@@ -5583,12 +6436,21 @@
mbedtls_ssl_send_flight_completed( ssl );
#endif
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM &&
+ ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flight_transmit", ret );
+ return( ret );
+ }
+#endif
+
MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) );
return( 0 );
@@ -5610,7 +6472,7 @@
ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 );
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret );
return( ret );
@@ -5841,6 +6703,78 @@
}
#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */
+/* Once ssl->out_hdr as the address of the beginning of the
+ * next outgoing record is set, deduce the other pointers.
+ *
+ * Note: For TLS, we save the implicit record sequence number
+ * (entering MAC computation) in the 8 bytes before ssl->out_hdr,
+ * and the caller has to make sure there's space for this.
+ */
+
+static void ssl_update_out_pointers( mbedtls_ssl_context *ssl,
+ mbedtls_ssl_transform *transform )
+{
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ {
+ ssl->out_ctr = ssl->out_hdr + 3;
+ ssl->out_len = ssl->out_hdr + 11;
+ ssl->out_iv = ssl->out_hdr + 13;
+ }
+ else
+#endif
+ {
+ ssl->out_ctr = ssl->out_hdr - 8;
+ ssl->out_len = ssl->out_hdr + 3;
+ ssl->out_iv = ssl->out_hdr + 5;
+ }
+
+ /* Adjust out_msg to make space for explicit IV, if used. */
+ if( transform != NULL &&
+ ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+ {
+ ssl->out_msg = ssl->out_iv + transform->ivlen - transform->fixed_ivlen;
+ }
+ else
+ ssl->out_msg = ssl->out_iv;
+}
+
+/* Once ssl->in_hdr as the address of the beginning of the
+ * next incoming record is set, deduce the other pointers.
+ *
+ * Note: For TLS, we save the implicit record sequence number
+ * (entering MAC computation) in the 8 bytes before ssl->in_hdr,
+ * and the caller has to make sure there's space for this.
+ */
+
+static void ssl_update_in_pointers( mbedtls_ssl_context *ssl,
+ mbedtls_ssl_transform *transform )
+{
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ {
+ ssl->in_ctr = ssl->in_hdr + 3;
+ ssl->in_len = ssl->in_hdr + 11;
+ ssl->in_iv = ssl->in_hdr + 13;
+ }
+ else
+#endif
+ {
+ ssl->in_ctr = ssl->in_hdr - 8;
+ ssl->in_len = ssl->in_hdr + 3;
+ ssl->in_iv = ssl->in_hdr + 5;
+ }
+
+ /* Offset in_msg from in_iv to allow space for explicit IV, if used. */
+ if( transform != NULL &&
+ ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+ {
+ ssl->in_msg = ssl->in_iv + transform->ivlen - transform->fixed_ivlen;
+ }
+ else
+ ssl->in_msg = ssl->in_iv;
+}
+
/*
* Initialize an SSL context
*/
@@ -5852,6 +6786,28 @@
/*
* Setup an SSL context
*/
+
+static void ssl_reset_in_out_pointers( mbedtls_ssl_context *ssl )
+{
+ /* Set the incoming and outgoing record pointers. */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+ {
+ ssl->out_hdr = ssl->out_buf;
+ ssl->in_hdr = ssl->in_buf;
+ }
+ else
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+ {
+ ssl->out_hdr = ssl->out_buf + 8;
+ ssl->in_hdr = ssl->in_buf + 8;
+ }
+
+ /* Derive other internal pointers. */
+ ssl_update_out_pointers( ssl, NULL /* no transform enabled */ );
+ ssl_update_in_pointers ( ssl, NULL /* no transform enabled */ );
+}
+
int mbedtls_ssl_setup( mbedtls_ssl_context *ssl,
const mbedtls_ssl_config *conf )
{
@@ -5862,57 +6818,55 @@
/*
* Prepare base structures
*/
+
+ /* Set to NULL in case of an error condition */
+ ssl->out_buf = NULL;
+
ssl->in_buf = mbedtls_calloc( 1, MBEDTLS_SSL_IN_BUFFER_LEN );
if( ssl->in_buf == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_IN_BUFFER_LEN) );
- return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+ ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ goto error;
}
ssl->out_buf = mbedtls_calloc( 1, MBEDTLS_SSL_OUT_BUFFER_LEN );
if( ssl->out_buf == NULL )
{
MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", MBEDTLS_SSL_OUT_BUFFER_LEN) );
- mbedtls_free( ssl->in_buf );
- ssl->in_buf = NULL;
- return( MBEDTLS_ERR_SSL_ALLOC_FAILED );
+ ret = MBEDTLS_ERR_SSL_ALLOC_FAILED;
+ goto error;
}
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
- if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
- {
- ssl->out_hdr = ssl->out_buf;
- ssl->out_ctr = ssl->out_buf + 3;
- ssl->out_len = ssl->out_buf + 11;
- ssl->out_iv = ssl->out_buf + 13;
- ssl->out_msg = ssl->out_buf + 13;
-
- ssl->in_hdr = ssl->in_buf;
- ssl->in_ctr = ssl->in_buf + 3;
- ssl->in_len = ssl->in_buf + 11;
- ssl->in_iv = ssl->in_buf + 13;
- ssl->in_msg = ssl->in_buf + 13;
- }
- else
-#endif
- {
- ssl->out_ctr = ssl->out_buf;
- ssl->out_hdr = ssl->out_buf + 8;
- ssl->out_len = ssl->out_buf + 11;
- ssl->out_iv = ssl->out_buf + 13;
- ssl->out_msg = ssl->out_buf + 13;
-
- ssl->in_ctr = ssl->in_buf;
- ssl->in_hdr = ssl->in_buf + 8;
- ssl->in_len = ssl->in_buf + 11;
- ssl->in_iv = ssl->in_buf + 13;
- ssl->in_msg = ssl->in_buf + 13;
- }
+ ssl_reset_in_out_pointers( ssl );
if( ( ret = ssl_handshake_init( ssl ) ) != 0 )
- return( ret );
+ goto error;
return( 0 );
+
+error:
+ mbedtls_free( ssl->in_buf );
+ mbedtls_free( ssl->out_buf );
+
+ ssl->conf = NULL;
+
+ ssl->in_buf = NULL;
+ ssl->out_buf = NULL;
+
+ ssl->in_hdr = NULL;
+ ssl->in_ctr = NULL;
+ ssl->in_len = NULL;
+ ssl->in_iv = NULL;
+ ssl->in_msg = NULL;
+
+ ssl->out_hdr = NULL;
+ ssl->out_ctr = NULL;
+ ssl->out_len = NULL;
+ ssl->out_iv = NULL;
+ ssl->out_msg = NULL;
+
+ return( ret );
}
/*
@@ -5926,6 +6880,11 @@
{
int ret;
+#if !defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) || \
+ !defined(MBEDTLS_SSL_SRV_C)
+ ((void) partial);
+#endif
+
ssl->state = MBEDTLS_SSL_HELLO_REQUEST;
/* Cancel any possibly running timer */
@@ -5942,12 +6901,10 @@
ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION;
ssl->in_offt = NULL;
+ ssl_reset_in_out_pointers( ssl );
- ssl->in_msg = ssl->in_buf + 13;
ssl->in_msgtype = 0;
ssl->in_msglen = 0;
- if( partial == 0 )
- ssl->in_left = 0;
#if defined(MBEDTLS_SSL_PROTO_DTLS)
ssl->next_record_offset = 0;
ssl->in_epoch = 0;
@@ -5961,7 +6918,6 @@
ssl->keep_current_message = 0;
- ssl->out_msg = ssl->out_buf + 13;
ssl->out_msgtype = 0;
ssl->out_msglen = 0;
ssl->out_left = 0;
@@ -5970,6 +6926,8 @@
ssl->split_done = 0;
#endif
+ memset( ssl->cur_out_ctr, 0, sizeof( ssl->cur_out_ctr ) );
+
ssl->transform_in = NULL;
ssl->transform_out = NULL;
@@ -5977,8 +6935,14 @@
ssl->session_out = NULL;
memset( ssl->out_buf, 0, MBEDTLS_SSL_OUT_BUFFER_LEN );
+
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C)
if( partial == 0 )
+#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */
+ {
+ ssl->in_left = 0;
memset( ssl->in_buf, 0, MBEDTLS_SSL_IN_BUFFER_LEN );
+ }
#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL)
if( mbedtls_ssl_hw_record_reset != NULL )
@@ -6011,7 +6975,9 @@
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C)
+#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE)
if( partial == 0 )
+#endif
{
mbedtls_free( ssl->cli_id );
ssl->cli_id = NULL;
@@ -6062,7 +7028,15 @@
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS)
-void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max )
+
+void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl,
+ unsigned allow_packing )
+{
+ ssl->disable_datagram_packing = !allow_packing;
+}
+
+void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf,
+ uint32_t min, uint32_t max )
{
conf->hs_timeout_min = min;
conf->hs_timeout_max = max;
@@ -6112,6 +7086,13 @@
ssl->f_recv_timeout = f_recv_timeout;
}
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu )
+{
+ ssl->mtu = mtu;
+}
+#endif
+
void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout )
{
conf->read_timeout = timeout;
@@ -6775,7 +7756,7 @@
/*
* In all other cases, the rest of the message can be dropped.
- * As in ssl_read_record_layer, this needs to be adapted if
+ * As in ssl_get_next_record, this needs to be adapted if
* we implement support for multiple alerts in single records.
*/
@@ -6842,8 +7823,9 @@
int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl )
{
- size_t transform_expansion;
+ size_t transform_expansion = 0;
const mbedtls_ssl_transform *transform = ssl->transform_out;
+ unsigned block_size;
if( transform == NULL )
return( (int) mbedtls_ssl_hdr_len( ssl ) );
@@ -6857,13 +7839,31 @@
{
case MBEDTLS_MODE_GCM:
case MBEDTLS_MODE_CCM:
+ case MBEDTLS_MODE_CHACHAPOLY:
case MBEDTLS_MODE_STREAM:
transform_expansion = transform->minlen;
break;
case MBEDTLS_MODE_CBC:
- transform_expansion = transform->maclen
- + mbedtls_cipher_get_block_size( &transform->cipher_ctx_enc );
+
+ block_size = mbedtls_cipher_get_block_size(
+ &transform->cipher_ctx_enc );
+
+ /* Expansion due to the addition of the MAC. */
+ transform_expansion += transform->maclen;
+
+ /* Expansion due to the addition of CBC padding;
+ * Theoretically up to 256 bytes, but we never use
+ * more than the block size of the underlying cipher. */
+ transform_expansion += block_size;
+
+ /* For TLS 1.1 or higher, an explicit IV is added
+ * after the record header. */
+#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2)
+ if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 )
+ transform_expansion += block_size;
+#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */
+
break;
default:
@@ -6884,19 +7884,83 @@
*/
max_len = ssl_mfl_code_to_length( ssl->conf->mfl_code );
- /*
- * Check if a smaller max length was negotiated
- */
+ /* Check if a smaller max length was negotiated */
if( ssl->session_out != NULL &&
ssl_mfl_code_to_length( ssl->session_out->mfl_code ) < max_len )
{
max_len = ssl_mfl_code_to_length( ssl->session_out->mfl_code );
}
- return max_len;
+ /* During a handshake, use the value being negotiated */
+ if( ssl->session_negotiate != NULL &&
+ ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code ) < max_len )
+ {
+ max_len = ssl_mfl_code_to_length( ssl->session_negotiate->mfl_code );
+ }
+
+ return( max_len );
}
#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+static size_t ssl_get_current_mtu( const mbedtls_ssl_context *ssl )
+{
+ if( ssl->handshake == NULL || ssl->handshake->mtu == 0 )
+ return( ssl->mtu );
+
+ if( ssl->mtu == 0 )
+ return( ssl->handshake->mtu );
+
+ return( ssl->mtu < ssl->handshake->mtu ?
+ ssl->mtu : ssl->handshake->mtu );
+}
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+int mbedtls_ssl_get_max_out_record_payload( const mbedtls_ssl_context *ssl )
+{
+ size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
+
+#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \
+ !defined(MBEDTLS_SSL_PROTO_DTLS)
+ (void) ssl;
+#endif
+
+#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
+ const size_t mfl = mbedtls_ssl_get_max_frag_len( ssl );
+
+ if( max_len > mfl )
+ max_len = mfl;
+#endif
+
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( ssl_get_current_mtu( ssl ) != 0 )
+ {
+ const size_t mtu = ssl_get_current_mtu( ssl );
+ const int ret = mbedtls_ssl_get_record_expansion( ssl );
+ const size_t overhead = (size_t) ret;
+
+ if( ret < 0 )
+ return( ret );
+
+ if( mtu <= overhead )
+ {
+ MBEDTLS_SSL_DEBUG_MSG( 1, ( "MTU too low for record expansion" ) );
+ return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE );
+ }
+
+ if( max_len > mtu - overhead )
+ max_len = mtu - overhead;
+ }
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
+#if !defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) && \
+ !defined(MBEDTLS_SSL_PROTO_DTLS)
+ ((void) ssl);
+#endif
+
+ return( (int) max_len );
+}
+
#if defined(MBEDTLS_X509_CRT_PARSE_C)
const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl )
{
@@ -6984,9 +8048,9 @@
ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE;
ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_REQUEST;
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_handshake_msg( ssl ) ) != 0 )
{
- MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_handshake_msg", ret );
return( ret );
}
@@ -7116,7 +8180,7 @@
in_ctr_cmp = memcmp( ssl->in_ctr + ep_len,
ssl->conf->renego_period + ep_len, 8 - ep_len );
- out_ctr_cmp = memcmp( ssl->out_ctr + ep_len,
+ out_ctr_cmp = memcmp( ssl->cur_out_ctr + ep_len,
ssl->conf->renego_period + ep_len, 8 - ep_len );
if( in_ctr_cmp <= 0 && out_ctr_cmp <= 0 )
@@ -7151,7 +8215,7 @@
if( ssl->handshake != NULL &&
ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING )
{
- if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_flight_transmit( ssl ) ) != 0 )
return( ret );
}
}
@@ -7200,7 +8264,7 @@
ssl_set_timer( ssl, ssl->conf->read_timeout );
}
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
if( ret == MBEDTLS_ERR_SSL_CONN_EOF )
return( 0 );
@@ -7215,7 +8279,7 @@
/*
* OpenSSL sends empty messages to randomize the IV
*/
- if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_read_record( ssl, 1 ) ) != 0 )
{
if( ret == MBEDTLS_ERR_SSL_CONN_EOF )
return( 0 );
@@ -7448,12 +8512,15 @@
static int ssl_write_real( mbedtls_ssl_context *ssl,
const unsigned char *buf, size_t len )
{
- int ret;
-#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
- size_t max_len = mbedtls_ssl_get_max_frag_len( ssl );
-#else
- size_t max_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
-#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */
+ int ret = mbedtls_ssl_get_max_out_record_payload( ssl );
+ const size_t max_len = (size_t) ret;
+
+ if( ret < 0 )
+ {
+ MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_get_max_out_record_payload", ret );
+ return( ret );
+ }
+
if( len > max_len )
{
#if defined(MBEDTLS_SSL_PROTO_DTLS)
@@ -7494,7 +8561,7 @@
ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA;
memcpy( ssl->out_msg, buf, len );
- if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 )
+ if( ( ret = mbedtls_ssl_write_record( ssl, SSL_FORCE_FLUSH ) ) != 0 )
{
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret );
return( ret );
@@ -7646,6 +8713,41 @@
}
#endif /* MBEDTLS_X509_CRT_PARSE_C */
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+
+static void ssl_buffering_free( mbedtls_ssl_context *ssl )
+{
+ unsigned offset;
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+
+ if( hs == NULL )
+ return;
+
+ ssl_free_buffered_record( ssl );
+
+ for( offset = 0; offset < MBEDTLS_SSL_MAX_BUFFERED_HS; offset++ )
+ ssl_buffering_free_slot( ssl, offset );
+}
+
+static void ssl_buffering_free_slot( mbedtls_ssl_context *ssl,
+ uint8_t slot )
+{
+ mbedtls_ssl_handshake_params * const hs = ssl->handshake;
+ mbedtls_ssl_hs_buffer * const hs_buf = &hs->buffering.hs[slot];
+
+ if( slot >= MBEDTLS_SSL_MAX_BUFFERED_HS )
+ return;
+
+ if( hs_buf->is_valid == 1 )
+ {
+ hs->buffering.total_bytes_buffered -= hs_buf->data_len;
+ mbedtls_free( hs_buf->data );
+ memset( hs_buf, 0, sizeof( mbedtls_ssl_hs_buffer ) );
+ }
+}
+
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
void mbedtls_ssl_handshake_free( mbedtls_ssl_context *ssl )
{
mbedtls_ssl_handshake_params *handshake = ssl->handshake;
@@ -7725,8 +8827,8 @@
#if defined(MBEDTLS_SSL_PROTO_DTLS)
mbedtls_free( handshake->verify_cookie );
- mbedtls_free( handshake->hs_msg );
ssl_flight_free( handshake->flight );
+ ssl_buffering_free( ssl );
#endif
mbedtls_platform_zeroize( handshake,
diff --git a/library/threading.c b/library/threading.c
index 7a32e67..7c90c7c 100644
--- a/library/threading.c
+++ b/library/threading.c
@@ -19,6 +19,14 @@
* This file is part of mbed TLS (https://tls.mbed.org)
*/
+/*
+ * Ensure gmtime_r is available even with -std=c99; must be defined before
+ * config.h, which pulls in glibc's features.h. Harmless on other platforms.
+ */
+#if !defined(_POSIX_C_SOURCE)
+#define _POSIX_C_SOURCE 200112L
+#endif
+
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
@@ -29,6 +37,36 @@
#include "mbedtls/threading.h"
+#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT)
+
+#if !defined(_WIN32) && (defined(unix) || \
+ defined(__unix) || defined(__unix__) || (defined(__APPLE__) && \
+ defined(__MACH__)))
+#include <unistd.h>
+#endif /* !_WIN32 && (unix || __unix || __unix__ ||
+ * (__APPLE__ && __MACH__)) */
+
+#if !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
+ ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) )
+/*
+ * This is a convenience shorthand macro to avoid checking the long
+ * preprocessor conditions above. Ideally, we could expose this macro in
+ * platform_util.h and simply use it in platform_util.c, threading.c and
+ * threading.h. However, this macro is not part of the Mbed TLS public API, so
+ * we keep it private by only defining it in this file
+ */
+
+#if ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) )
+#define THREADING_USE_GMTIME
+#endif /* ! ( defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) ) */
+
+#endif /* !( ( defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L ) || \
+ ( defined(_POSIX_THREAD_SAFE_FUNCTIONS ) && \
+ _POSIX_THREAD_SAFE_FUNCTIONS >= 20112L ) ) */
+
+#endif /* MBEDTLS_HAVE_TIME_DATE && !MBEDTLS_PLATFORM_GMTIME_R_ALT */
+
#if defined(MBEDTLS_THREADING_PTHREAD)
static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex )
{
@@ -114,6 +152,9 @@
#if defined(MBEDTLS_FS_IO)
mbedtls_mutex_init( &mbedtls_threading_readdir_mutex );
#endif
+#if defined(THREADING_USE_GMTIME)
+ mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex );
+#endif
}
/*
@@ -124,6 +165,9 @@
#if defined(MBEDTLS_FS_IO)
mbedtls_mutex_free( &mbedtls_threading_readdir_mutex );
#endif
+#if defined(THREADING_USE_GMTIME)
+ mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex );
+#endif
}
#endif /* MBEDTLS_THREADING_ALT */
@@ -136,5 +180,8 @@
#if defined(MBEDTLS_FS_IO)
mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT;
#endif
+#if defined(THREADING_USE_GMTIME)
+mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT;
+#endif
#endif /* MBEDTLS_THREADING_C */
diff --git a/library/x509.c b/library/x509.c
index 2e6795f..52b5b64 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -29,10 +29,6 @@
* http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf
*/
-/* Ensure gmtime_r is available even with -std=c99; must be included before
- * config.h, which pulls in glibc's features.h. Harmless on other platforms. */
-#define _POSIX_C_SOURCE 200112L
-
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
@@ -67,6 +63,7 @@
#include "mbedtls/platform_time.h"
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE)
+#include "mbedtls/platform_util.h"
#include <time.h>
#endif
@@ -901,11 +898,7 @@
int ret = 0;
tt = mbedtls_time( NULL );
-#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32)
- lt = gmtime_s( &tm_buf, &tt ) == 0 ? &tm_buf : NULL;
-#else
- lt = gmtime_r( &tt, &tm_buf );
-#endif
+ lt = mbedtls_platform_gmtime_r( &tt, &tm_buf );
if( lt == NULL )
ret = -1;
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 290c1eb..a390f81 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -163,6 +163,9 @@
static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile,
mbedtls_md_type_t md_alg )
{
+ if( md_alg == MBEDTLS_MD_NONE )
+ return( -1 );
+
if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 )
return( 0 );
@@ -176,6 +179,9 @@
static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile,
mbedtls_pk_type_t pk_alg )
{
+ if( pk_alg == MBEDTLS_PK_NONE )
+ return( -1 );
+
if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 )
return( 0 );
@@ -208,6 +214,9 @@
{
const mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id;
+ if( gid == MBEDTLS_ECP_DP_NONE )
+ return( -1 );
+
if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 )
return( 0 );
@@ -570,18 +579,14 @@
end_ext_data = *p + len;
/* Get extension ID */
- extn_oid.tag = **p;
-
- if( ( ret = mbedtls_asn1_get_tag( p, end, &extn_oid.len, MBEDTLS_ASN1_OID ) ) != 0 )
+ if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &extn_oid.len,
+ MBEDTLS_ASN1_OID ) ) != 0 )
return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+ extn_oid.tag = MBEDTLS_ASN1_OID;
extn_oid.p = *p;
*p += extn_oid.len;
- if( ( end - *p ) < 1 )
- return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
- MBEDTLS_ERR_ASN1_OUT_OF_DATA );
-
/* Get optional critical */
if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 &&
( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) )
diff --git a/programs/pkey/pk_decrypt.c b/programs/pkey/pk_decrypt.c
index 00bd71e..1d8c959 100644
--- a/programs/pkey/pk_decrypt.c
+++ b/programs/pkey/pk_decrypt.c
@@ -73,7 +73,10 @@
const char *pers = "mbedtls_pk_decrypt";
((void) argv);
+ mbedtls_pk_init( &pk );
+ mbedtls_entropy_init( &entropy );
mbedtls_ctr_drbg_init( &ctr_drbg );
+
memset(result, 0, sizeof( result ) );
if( argc != 2 )
@@ -90,20 +93,18 @@
mbedtls_printf( "\n . Seeding the random number generator..." );
fflush( stdout );
- mbedtls_entropy_init( &entropy );
- if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
- (const unsigned char *) pers,
- strlen( pers ) ) ) != 0 )
+ if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func,
+ &entropy, (const unsigned char *) pers,
+ strlen( pers ) ) ) != 0 )
{
- mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret );
+ mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned -0x%04x\n",
+ -ret );
goto exit;
}
mbedtls_printf( "\n . Reading private key from '%s'", argv[1] );
fflush( stdout );
- mbedtls_pk_init( &pk );
-
if( ( ret = mbedtls_pk_parse_keyfile( &pk, argv[1], "" ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_pk_parse_keyfile returned -0x%04x\n", -ret );
@@ -116,14 +117,16 @@
if( ( f = fopen( "result-enc.txt", "rb" ) ) == NULL )
{
mbedtls_printf( "\n ! Could not open %s\n\n", "result-enc.txt" );
+ ret = 1;
goto exit;
}
i = 0;
-
while( fscanf( f, "%02X", &c ) > 0 &&
i < (int) sizeof( buf ) )
+ {
buf[i++] = (unsigned char) c;
+ }
fclose( f );
@@ -136,7 +139,8 @@
if( ( ret = mbedtls_pk_decrypt( &pk, buf, i, result, &olen, sizeof(result),
mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
{
- mbedtls_printf( " failed\n ! mbedtls_pk_decrypt returned -0x%04x\n", -ret );
+ mbedtls_printf( " failed\n ! mbedtls_pk_decrypt returned -0x%04x\n",
+ -ret );
goto exit;
}
@@ -147,13 +151,15 @@
exit_code = MBEDTLS_EXIT_SUCCESS;
exit:
- mbedtls_ctr_drbg_free( &ctr_drbg );
+
+ mbedtls_pk_free( &pk );
mbedtls_entropy_free( &entropy );
+ mbedtls_ctr_drbg_free( &ctr_drbg );
#if defined(MBEDTLS_ERROR_C)
if( exit_code != MBEDTLS_EXIT_SUCCESS )
{
- mbedtls_strerror( ret, (char *) buf, sizeof(buf) );
+ mbedtls_strerror( ret, (char *) buf, sizeof( buf ) );
mbedtls_printf( " ! Last error was: %s\n", buf );
}
#endif
diff --git a/programs/pkey/pk_encrypt.c b/programs/pkey/pk_encrypt.c
index 400619c..22dedba 100644
--- a/programs/pkey/pk_encrypt.c
+++ b/programs/pkey/pk_encrypt.c
@@ -73,6 +73,8 @@
const char *pers = "mbedtls_pk_encrypt";
mbedtls_ctr_drbg_init( &ctr_drbg );
+ mbedtls_entropy_init( &entropy );
+ mbedtls_pk_init( &pk );
if( argc != 3 )
{
@@ -88,20 +90,18 @@
mbedtls_printf( "\n . Seeding the random number generator..." );
fflush( stdout );
- mbedtls_entropy_init( &entropy );
- if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
- (const unsigned char *) pers,
- strlen( pers ) ) ) != 0 )
+ if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func,
+ &entropy, (const unsigned char *) pers,
+ strlen( pers ) ) ) != 0 )
{
- mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned -0x%04x\n", -ret );
+ mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned -0x%04x\n",
+ -ret );
goto exit;
}
mbedtls_printf( "\n . Reading public key from '%s'", argv[1] );
fflush( stdout );
- mbedtls_pk_init( &pk );
-
if( ( ret = mbedtls_pk_parse_public_keyfile( &pk, argv[1] ) ) != 0 )
{
mbedtls_printf( " failed\n ! mbedtls_pk_parse_public_keyfile returned -0x%04x\n", -ret );
@@ -126,7 +126,8 @@
buf, &olen, sizeof(buf),
mbedtls_ctr_drbg_random, &ctr_drbg ) ) != 0 )
{
- mbedtls_printf( " failed\n ! mbedtls_pk_encrypt returned -0x%04x\n", -ret );
+ mbedtls_printf( " failed\n ! mbedtls_pk_encrypt returned -0x%04x\n",
+ -ret );
goto exit;
}
@@ -135,13 +136,17 @@
*/
if( ( f = fopen( "result-enc.txt", "wb+" ) ) == NULL )
{
- mbedtls_printf( " failed\n ! Could not create %s\n\n", "result-enc.txt" );
+ mbedtls_printf( " failed\n ! Could not create %s\n\n",
+ "result-enc.txt" );
+ ret = 1;
goto exit;
}
for( i = 0; i < olen; i++ )
+ {
mbedtls_fprintf( f, "%02X%s", buf[i],
( i + 1 ) % 16 == 0 ? "\r\n" : " " );
+ }
fclose( f );
@@ -150,13 +155,15 @@
exit_code = MBEDTLS_EXIT_SUCCESS;
exit:
- mbedtls_ctr_drbg_free( &ctr_drbg );
+
+ mbedtls_pk_free( &pk );
mbedtls_entropy_free( &entropy );
+ mbedtls_ctr_drbg_free( &ctr_drbg );
#if defined(MBEDTLS_ERROR_C)
if( exit_code != MBEDTLS_EXIT_SUCCESS )
{
- mbedtls_strerror( ret, (char *) buf, sizeof(buf) );
+ mbedtls_strerror( ret, (char *) buf, sizeof( buf ) );
mbedtls_printf( " ! Last error was: %s\n", buf );
}
#endif
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 0dd9e3f..efd2b30 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -106,6 +106,8 @@
#define DFL_TRANSPORT MBEDTLS_SSL_TRANSPORT_STREAM
#define DFL_HS_TO_MIN 0
#define DFL_HS_TO_MAX 0
+#define DFL_DTLS_MTU -1
+#define DFL_DGRAM_PACKING 1
#define DFL_FALLBACK -1
#define DFL_EXTENDED_MS -1
#define DFL_ETM -1
@@ -198,7 +200,11 @@
#define USAGE_DTLS \
" dtls=%%d default: 0 (TLS)\n" \
" hs_timeout=%%d-%%d default: (library default: 1000-60000)\n" \
- " range of DTLS handshake timeouts in millisecs\n"
+ " range of DTLS handshake timeouts in millisecs\n" \
+ " mtu=%%d default: (library default: unlimited)\n" \
+ " dgram_packing=%%d default: 1 (allowed)\n" \
+ " allow or forbid packing of multiple\n" \
+ " records within a single datgram.\n"
#else
#define USAGE_DTLS ""
#endif
@@ -345,7 +351,9 @@
int transport; /* TLS or DTLS? */
uint32_t hs_to_min; /* Initial value of DTLS handshake timer */
uint32_t hs_to_max; /* Max value of DTLS handshake timer */
+ int dtls_mtu; /* UDP Maximum tranport unit for DTLS */
int fallback; /* is this a fallback connection? */
+ int dgram_packing; /* allow/forbid datagram packing */
int extended_ms; /* negotiate extended master secret? */
int etm; /* negotiate encrypt then mac? */
} opt;
@@ -617,9 +625,11 @@
opt.transport = DFL_TRANSPORT;
opt.hs_to_min = DFL_HS_TO_MIN;
opt.hs_to_max = DFL_HS_TO_MAX;
+ opt.dtls_mtu = DFL_DTLS_MTU;
opt.fallback = DFL_FALLBACK;
opt.extended_ms = DFL_EXTENDED_MS;
opt.etm = DFL_ETM;
+ opt.dgram_packing = DFL_DGRAM_PACKING;
for( i = 1; i < argc; i++ )
{
@@ -927,6 +937,21 @@
if( opt.hs_to_min == 0 || opt.hs_to_max < opt.hs_to_min )
goto usage;
}
+ else if( strcmp( p, "mtu" ) == 0 )
+ {
+ opt.dtls_mtu = atoi( q );
+ if( opt.dtls_mtu < 0 )
+ goto usage;
+ }
+ else if( strcmp( p, "dgram_packing" ) == 0 )
+ {
+ opt.dgram_packing = atoi( q );
+ if( opt.dgram_packing != 0 &&
+ opt.dgram_packing != 1 )
+ {
+ goto usage;
+ }
+ }
else if( strcmp( p, "recsplit" ) == 0 )
{
opt.recsplit = atoi( q );
@@ -1327,6 +1352,9 @@
if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX )
mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min,
opt.hs_to_max );
+
+ if( opt.dgram_packing != DFL_DGRAM_PACKING )
+ mbedtls_ssl_set_datagram_packing( &ssl, opt.dgram_packing );
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
@@ -1485,6 +1513,11 @@
mbedtls_net_send, mbedtls_net_recv,
opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( opt.dtls_mtu != DFL_DTLS_MTU )
+ mbedtls_ssl_set_mtu( &ssl, opt.dtls_mtu );
+#endif
+
#if defined(MBEDTLS_TIMING_C)
mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
mbedtls_timing_get_delay );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 7654a64..070c005 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -150,7 +150,9 @@
#define DFL_ANTI_REPLAY -1
#define DFL_HS_TO_MIN 0
#define DFL_HS_TO_MAX 0
+#define DFL_DTLS_MTU -1
#define DFL_BADMAC_LIMIT -1
+#define DFL_DGRAM_PACKING 1
#define DFL_EXTENDED_MS -1
#define DFL_ETM -1
@@ -297,7 +299,11 @@
#define USAGE_DTLS \
" dtls=%%d default: 0 (TLS)\n" \
" hs_timeout=%%d-%%d default: (library default: 1000-60000)\n" \
- " range of DTLS handshake timeouts in millisecs\n"
+ " range of DTLS handshake timeouts in millisecs\n" \
+ " mtu=%%d default: (library default: unlimited)\n" \
+ " dgram_packing=%%d default: 1 (allowed)\n" \
+ " allow or forbid packing of multiple\n" \
+ " records within a single datgram.\n"
#else
#define USAGE_DTLS ""
#endif
@@ -470,6 +476,8 @@
int anti_replay; /* Use anti-replay for DTLS? -1 for default */
uint32_t hs_to_min; /* Initial value of DTLS handshake timer */
uint32_t hs_to_max; /* Max value of DTLS handshake timer */
+ int dtls_mtu; /* UDP Maximum tranport unit for DTLS */
+ int dgram_packing; /* allow/forbid datagram packing */
int badmac_limit; /* Limit of records with bad MAC */
} opt;
@@ -1338,6 +1346,8 @@
opt.anti_replay = DFL_ANTI_REPLAY;
opt.hs_to_min = DFL_HS_TO_MIN;
opt.hs_to_max = DFL_HS_TO_MAX;
+ opt.dtls_mtu = DFL_DTLS_MTU;
+ opt.dgram_packing = DFL_DGRAM_PACKING;
opt.badmac_limit = DFL_BADMAC_LIMIT;
opt.extended_ms = DFL_EXTENDED_MS;
opt.etm = DFL_ETM;
@@ -1684,6 +1694,21 @@
if( opt.hs_to_min == 0 || opt.hs_to_max < opt.hs_to_min )
goto usage;
}
+ else if( strcmp( p, "mtu" ) == 0 )
+ {
+ opt.dtls_mtu = atoi( q );
+ if( opt.dtls_mtu < 0 )
+ goto usage;
+ }
+ else if( strcmp( p, "dgram_packing" ) == 0 )
+ {
+ opt.dgram_packing = atoi( q );
+ if( opt.dgram_packing != 0 &&
+ opt.dgram_packing != 1 )
+ {
+ goto usage;
+ }
+ }
else if( strcmp( p, "sni" ) == 0 )
{
opt.sni = q;
@@ -2155,6 +2180,9 @@
#if defined(MBEDTLS_SSL_PROTO_DTLS)
if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX )
mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min, opt.hs_to_max );
+
+ if( opt.dgram_packing != DFL_DGRAM_PACKING )
+ mbedtls_ssl_set_datagram_packing( &ssl, opt.dgram_packing );
#endif /* MBEDTLS_SSL_PROTO_DTLS */
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
@@ -2473,6 +2501,11 @@
mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv,
opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+ if( opt.dtls_mtu != DFL_DTLS_MTU )
+ mbedtls_ssl_set_mtu( &ssl, opt.dtls_mtu );
+#endif
+
#if defined(MBEDTLS_TIMING_C)
mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
mbedtls_timing_get_delay );
diff --git a/programs/test/udp_proxy.c b/programs/test/udp_proxy.c
index 55e0f24..41739d0 100644
--- a/programs/test/udp_proxy.c
+++ b/programs/test/udp_proxy.c
@@ -40,6 +40,8 @@
#define mbedtls_time time
#define mbedtls_time_t time_t
#define mbedtls_printf printf
+#define mbedtls_calloc calloc
+#define mbedtls_free free
#define MBEDTLS_EXIT_SUCCESS EXIT_SUCCESS
#define MBEDTLS_EXIT_FAILURE EXIT_FAILURE
#endif /* MBEDTLS_PLATFORM_C */
@@ -106,6 +108,21 @@
" delay=%%d default: 0 (no delayed packets)\n" \
" delay about 1:N packets randomly\n" \
" delay_ccs=0/1 default: 0 (don't delay ChangeCipherSpec)\n" \
+ " delay_cli=%%s Handshake message from client that should be\n"\
+ " delayed. Possible values are 'ClientHello',\n" \
+ " 'Certificate', 'CertificateVerify', and\n" \
+ " 'ClientKeyExchange'.\n" \
+ " May be used multiple times, even for the same\n"\
+ " message, in which case the respective message\n"\
+ " gets delayed multiple times.\n" \
+ " delay_srv=%%s Handshake message from server that should be\n"\
+ " delayed. Possible values are 'HelloRequest',\n"\
+ " 'ServerHello', 'ServerHelloDone', 'Certificate'\n"\
+ " 'ServerKeyExchange', 'NewSessionTicket',\n"\
+ " 'HelloVerifyRequest' and ''CertificateRequest'.\n"\
+ " May be used multiple times, even for the same\n"\
+ " message, in which case the respective message\n"\
+ " gets delayed multiple times.\n" \
" drop=%%d default: 0 (no dropped packets)\n" \
" drop about 1:N packets randomly\n" \
" mtu=%%d default: 0 (unlimited)\n" \
@@ -121,6 +138,9 @@
/*
* global options
*/
+
+#define MAX_DELAYED_HS 10
+
static struct options
{
const char *server_addr; /* address to forward packets to */
@@ -131,6 +151,12 @@
int duplicate; /* duplicate 1 in N packets (none if 0) */
int delay; /* delay 1 packet in N (none if 0) */
int delay_ccs; /* delay ChangeCipherSpec */
+ char* delay_cli[MAX_DELAYED_HS]; /* handshake types of messages from
+ * client that should be delayed. */
+ uint8_t delay_cli_cnt; /* Number of entries in delay_cli. */
+ char* delay_srv[MAX_DELAYED_HS]; /* handshake types of messages from
+ * server that should be delayed. */
+ uint8_t delay_srv_cnt; /* Number of entries in delay_srv. */
int drop; /* drop 1 packet in N (none if 0) */
int mtu; /* drop packets larger than this */
int bad_ad; /* inject corrupted ApplicationData record */
@@ -164,6 +190,11 @@
opt.pack = DFL_PACK;
/* Other members default to 0 */
+ opt.delay_cli_cnt = 0;
+ opt.delay_srv_cnt = 0;
+ memset( opt.delay_cli, 0, sizeof( opt.delay_cli ) );
+ memset( opt.delay_srv, 0, sizeof( opt.delay_srv ) );
+
for( i = 1; i < argc; i++ )
{
p = argv[i];
@@ -197,6 +228,43 @@
if( opt.delay_ccs < 0 || opt.delay_ccs > 1 )
exit_usage( p, q );
}
+ else if( strcmp( p, "delay_cli" ) == 0 ||
+ strcmp( p, "delay_srv" ) == 0 )
+ {
+ uint8_t *delay_cnt;
+ char **delay_list;
+ size_t len;
+ char *buf;
+
+ if( strcmp( p, "delay_cli" ) == 0 )
+ {
+ delay_cnt = &opt.delay_cli_cnt;
+ delay_list = opt.delay_cli;
+ }
+ else
+ {
+ delay_cnt = &opt.delay_srv_cnt;
+ delay_list = opt.delay_srv;
+ }
+
+ if( *delay_cnt == MAX_DELAYED_HS )
+ {
+ mbedtls_printf( " too many uses of %s: only %d allowed\n",
+ p, MAX_DELAYED_HS );
+ exit_usage( p, NULL );
+ }
+
+ len = strlen( q );
+ buf = mbedtls_calloc( 1, len + 1 );
+ if( buf == NULL )
+ {
+ mbedtls_printf( " Allocation failure\n" );
+ exit( 1 );
+ }
+ memcpy( buf, q, len + 1 );
+
+ delay_list[ (*delay_cnt)++ ] = buf;
+ }
else if( strcmp( p, "drop" ) == 0 )
{
opt.drop = atoi( q );
@@ -488,11 +556,37 @@
return( 0 );
}
-static packet prev;
+#define MAX_DELAYED_MSG 5
+static size_t prev_len;
+static packet prev[MAX_DELAYED_MSG];
void clear_pending( void )
{
- memset( &prev, 0, sizeof( packet ) );
+ memset( &prev, 0, sizeof( prev ) );
+ prev_len = 0;
+}
+
+void delay_packet( packet *delay )
+{
+ if( prev_len == MAX_DELAYED_MSG )
+ return;
+
+ memcpy( &prev[prev_len++], delay, sizeof( packet ) );
+}
+
+int send_delayed()
+{
+ uint8_t offset;
+ int ret;
+ for( offset = 0; offset < prev_len; offset++ )
+ {
+ ret = send_packet( &prev[offset], "delayed" );
+ if( ret != 0 )
+ return( ret );
+ }
+
+ clear_pending();
+ return( 0 );
}
/*
@@ -540,6 +634,10 @@
packet cur;
size_t id;
+ uint8_t delay_idx;
+ char ** delay_list;
+ uint8_t delay_list_len;
+
/* receive packet */
if( ( ret = mbedtls_net_recv( src, cur.buf, sizeof( cur.buf ) ) ) <= 0 )
{
@@ -555,6 +653,37 @@
id = cur.len % sizeof( dropped );
+ if( strcmp( way, "S <- C" ) == 0 )
+ {
+ delay_list = opt.delay_cli;
+ delay_list_len = opt.delay_cli_cnt;
+ }
+ else
+ {
+ delay_list = opt.delay_srv;
+ delay_list_len = opt.delay_srv_cnt;
+ }
+
+ /* Check if message type is in the list of messages
+ * that should be delayed */
+ for( delay_idx = 0; delay_idx < delay_list_len; delay_idx++ )
+ {
+ if( delay_list[ delay_idx ] == NULL )
+ continue;
+
+ if( strcmp( delay_list[ delay_idx ], cur.type ) == 0 )
+ {
+ /* Delay message */
+ delay_packet( &cur );
+
+ /* Remove entry from list */
+ mbedtls_free( delay_list[delay_idx] );
+ delay_list[delay_idx] = NULL;
+
+ return( 0 );
+ }
+ }
+
/* do we want to drop, delay, or forward it? */
if( ( opt.mtu != 0 &&
cur.len > (unsigned) opt.mtu ) ||
@@ -574,12 +703,11 @@
strcmp( cur.type, "ApplicationData" ) != 0 &&
! ( opt.protect_hvr &&
strcmp( cur.type, "HelloVerifyRequest" ) == 0 ) &&
- prev.dst == NULL &&
cur.len != (size_t) opt.protect_len &&
dropped[id] < DROP_MAX &&
rand() % opt.delay == 0 ) )
{
- memcpy( &prev, &cur, sizeof( packet ) );
+ delay_packet( &cur );
}
else
{
@@ -587,14 +715,10 @@
if( ( ret = send_packet( &cur, "forwarded" ) ) != 0 )
return( ret );
- /* send previously delayed message if any */
- if( prev.dst != NULL )
- {
- ret = send_packet( &prev, "delayed" );
- memset( &prev, 0, sizeof( packet ) );
- if( ret != 0 )
- return( ret );
- }
+ /* send previously delayed messages if any */
+ ret = send_delayed();
+ if( ret != 0 )
+ return( ret );
}
return( 0 );
@@ -604,6 +728,7 @@
{
int ret = 1;
int exit_code = MBEDTLS_EXIT_FAILURE;
+ uint8_t delay_idx;
mbedtls_net_context listen_fd, client_fd, server_fd;
@@ -798,6 +923,12 @@
}
#endif
+ for( delay_idx = 0; delay_idx < MAX_DELAYED_HS; delay_idx++ )
+ {
+ mbedtls_free( opt.delay_cli + delay_idx );
+ mbedtls_free( opt.delay_srv + delay_idx );
+ }
+
mbedtls_net_free( &client_fd );
mbedtls_net_free( &server_fd );
mbedtls_net_free( &listen_fd );
diff --git a/programs/x509/cert_write.c b/programs/x509/cert_write.c
index 09a91e0..fa99461 100644
--- a/programs/x509/cert_write.c
+++ b/programs/x509/cert_write.c
@@ -164,7 +164,7 @@
const char *issuer_key; /* filename of the issuer key file */
const char *subject_pwd; /* password for the subject key file */
const char *issuer_pwd; /* password for the issuer key file */
- const char *output_file; /* where to store the constructed key file */
+ const char *output_file; /* where to store the constructed CRT */
const char *subject_name; /* subject name for certificate */
const char *issuer_name; /* issuer name for certificate */
const char *not_before; /* validity period not before */
@@ -770,7 +770,7 @@
}
/*
- * 1.2. Writing the request
+ * 1.2. Writing the certificate
*/
mbedtls_printf( " . Writing the certificate..." );
fflush( stdout );
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index ca9c93e..1faa5d5 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -558,6 +558,26 @@
msg "test: small SSL_IN_CONTENT_LEN - ssl-opt.sh MFL tests"
if_build_succeeded tests/ssl-opt.sh -f "Max fragment"
+msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0"
+cleanup
+cp "$CONFIG_H" "$CONFIG_BAK"
+scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 1000
+CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+make
+
+msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #0 - ssl-opt.sh specific reordering test"
+if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg"
+
+msg "build: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1"
+cleanup
+cp "$CONFIG_H" "$CONFIG_BAK"
+scripts/config.pl set MBEDTLS_SSL_DTLS_MAX_BUFFERING 240
+CC=gcc cmake -D CMAKE_BUILD_TYPE:String=Asan .
+make
+
+msg "test: small MBEDTLS_SSL_DTLS_MAX_BUFFERING #1 - ssl-opt.sh specific reordering test"
+if_build_succeeded tests/ssl-opt.sh -f "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket"
+
msg "build: cmake, full config, clang" # ~ 50s
cleanup
cp "$CONFIG_H" "$CONFIG_BAK"
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index 92b7686..30d1ebb 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -41,6 +41,28 @@
G_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_CLI --x509cafile data_files/test-ca_cat12.crt"
TCP_CLIENT="$PERL scripts/tcp_client.pl"
+# alternative versions of OpenSSL and GnuTLS (no default path)
+
+if [ -n "${OPENSSL_LEGACY:-}" ]; then
+ O_LEGACY_SRV="$OPENSSL_LEGACY s_server -www -cert data_files/server5.crt -key data_files/server5.key"
+ O_LEGACY_CLI="echo 'GET / HTTP/1.0' | $OPENSSL_LEGACY s_client"
+else
+ O_LEGACY_SRV=false
+ O_LEGACY_CLI=false
+fi
+
+if [ -n "${GNUTLS_NEXT_SERV:-}" ]; then
+ G_NEXT_SRV="$GNUTLS_NEXT_SERV --x509certfile data_files/server5.crt --x509keyfile data_files/server5.key"
+else
+ G_NEXT_SRV=false
+fi
+
+if [ -n "${GNUTLS_NEXT_CLI:-}" ]; then
+ G_NEXT_CLI="echo 'GET / HTTP/1.0' | $GNUTLS_NEXT_CLI --x509cafile data_files/test-ca_cat12.crt"
+else
+ G_NEXT_CLI=false
+fi
+
TESTS=0
FAILS=0
SKIPS=0
@@ -120,6 +142,14 @@
done
}
+# Skip next test; use this macro to skip tests which are legitimate
+# in theory and expected to be re-introduced at some point, but
+# aren't expected to succeed at the moment due to problems outside
+# our control (such as bugs in other TLS implementations).
+skip_next_test() {
+ SKIP_NEXT="YES"
+}
+
# skip next test if the flag is not enabled in config.h
requires_config_enabled() {
if grep "^#define $1" $CONFIG_H > /dev/null; then :; else
@@ -134,6 +164,27 @@
fi
}
+get_config_value_or_default() {
+ NAME="$1"
+ DEF_VAL=$( grep ".*#define.*${NAME}" ../include/mbedtls/config.h |
+ sed 's/^.*\s\([0-9]*\)$/\1/' )
+ ../scripts/config.pl get $NAME || echo "$DEF_VAL"
+}
+
+requires_config_value_at_least() {
+ VAL=$( get_config_value_or_default "$1" )
+ if [ "$VAL" -lt "$2" ]; then
+ SKIP_NEXT="YES"
+ fi
+}
+
+requires_config_value_at_most() {
+ VAL=$( get_config_value_or_default "$1" )
+ if [ "$VAL" -gt "$2" ]; then
+ SKIP_NEXT="YES"
+ fi
+}
+
# skip next test if OpenSSL doesn't support FALLBACK_SCSV
requires_openssl_with_fallback_scsv() {
if [ -z "${OPENSSL_HAS_FBSCSV:-}" ]; then
@@ -163,6 +214,34 @@
fi
}
+# skip next test if GnuTLS-next isn't available
+requires_gnutls_next() {
+ if [ -z "${GNUTLS_NEXT_AVAILABLE:-}" ]; then
+ if ( which "${GNUTLS_NEXT_CLI:-}" && which "${GNUTLS_NEXT_SERV:-}" ) >/dev/null 2>&1; then
+ GNUTLS_NEXT_AVAILABLE="YES"
+ else
+ GNUTLS_NEXT_AVAILABLE="NO"
+ fi
+ fi
+ if [ "$GNUTLS_NEXT_AVAILABLE" = "NO" ]; then
+ SKIP_NEXT="YES"
+ fi
+}
+
+# skip next test if OpenSSL-legacy isn't available
+requires_openssl_legacy() {
+ if [ -z "${OPENSSL_LEGACY_AVAILABLE:-}" ]; then
+ if which "${OPENSSL_LEGACY:-}" >/dev/null 2>&1; then
+ OPENSSL_LEGACY_AVAILABLE="YES"
+ else
+ OPENSSL_LEGACY_AVAILABLE="NO"
+ fi
+ fi
+ if [ "$OPENSSL_LEGACY_AVAILABLE" = "NO" ]; then
+ SKIP_NEXT="YES"
+ fi
+}
+
# skip next test if IPv6 isn't available on this host
requires_ipv6() {
if [ -z "${HAS_IPV6:-}" ]; then
@@ -632,6 +711,9 @@
if [ "$PRESERVE_LOGS" -gt 0 ]; then
mv $SRV_OUT o-srv-${TESTS}.log
mv $CLI_OUT o-cli-${TESTS}.log
+ if [ -n "$PXY_CMD" ]; then
+ mv $PXY_OUT o-pxy-${TESTS}.log
+ fi
fi
rm -f $SRV_OUT $CLI_OUT $PXY_OUT
@@ -715,7 +797,20 @@
O_SRV="$O_SRV -accept $SRV_PORT -dhparam data_files/dhparams.pem"
O_CLI="$O_CLI -connect localhost:+SRV_PORT"
G_SRV="$G_SRV -p $SRV_PORT"
-G_CLI="$G_CLI -p +SRV_PORT localhost"
+G_CLI="$G_CLI -p +SRV_PORT"
+
+if [ -n "${OPENSSL_LEGACY:-}" ]; then
+ O_LEGACY_SRV="$O_LEGACY_SRV -accept $SRV_PORT -dhparam data_files/dhparams.pem"
+ O_LEGACY_CLI="$O_LEGACY_CLI -connect localhost:+SRV_PORT"
+fi
+
+if [ -n "${GNUTLS_NEXT_SERV:-}" ]; then
+ G_NEXT_SRV="$G_NEXT_SRV -p $SRV_PORT"
+fi
+
+if [ -n "${GNUTLS_NEXT_CLI:-}" ]; then
+ G_NEXT_CLI="$G_NEXT_CLI -p +SRV_PORT"
+fi
# Allow SHA-1, because many of our test certificates use it
P_SRV="$P_SRV allow_sha1=1"
@@ -801,6 +896,22 @@
-S "SSL - None of the common ciphersuites is usable" \
-S "SSL - The server has no ciphersuites in common"
+# Test empty CA list in CertificateRequest in TLS 1.1 and earlier
+
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+run_test "CertificateRequest with empty CA list, TLS 1.1 (GnuTLS server)" \
+ "$G_SRV"\
+ "$P_CLI force_version=tls1_1" \
+ 0
+
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1
+run_test "CertificateRequest with empty CA list, TLS 1.0 (GnuTLS server)" \
+ "$G_SRV"\
+ "$P_CLI force_version=tls1" \
+ 0
+
# Tests for SHA-1 support
requires_config_disabled MBEDTLS_TLS_DEFAULT_ALLOW_SHA1_IN_CERTIFICATES
@@ -849,6 +960,35 @@
"$P_CLI key_file=data_files/cli-rsa.key crt_file=data_files/cli-rsa-sha256.crt" \
0
+# Tests for datagram packing
+run_test "DTLS: multiple records in same datagram, client and server" \
+ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \
+ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \
+ 0 \
+ -c "next record in same datagram" \
+ -s "next record in same datagram"
+
+run_test "DTLS: multiple records in same datagram, client only" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \
+ "$P_CLI dtls=1 dgram_packing=1 debug_level=2" \
+ 0 \
+ -s "next record in same datagram" \
+ -C "next record in same datagram"
+
+run_test "DTLS: multiple records in same datagram, server only" \
+ "$P_SRV dtls=1 dgram_packing=1 debug_level=2" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \
+ 0 \
+ -S "next record in same datagram" \
+ -c "next record in same datagram"
+
+run_test "DTLS: multiple records in same datagram, neither client nor server" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \
+ 0 \
+ -S "next record in same datagram" \
+ -C "next record in same datagram"
+
# Tests for Truncated HMAC extension
run_test "Truncated HMAC: client default, server default" \
@@ -2215,7 +2355,7 @@
requires_gnutls
run_test "Renego ext: gnutls client strict, server default" \
"$P_SRV debug_level=3" \
- "$G_CLI --priority=NORMAL:%SAFE_RENEGOTIATION" \
+ "$G_CLI --priority=NORMAL:%SAFE_RENEGOTIATION localhost" \
0 \
-s "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \
-s "server hello, secure renegotiation extension"
@@ -2223,7 +2363,7 @@
requires_gnutls
run_test "Renego ext: gnutls client unsafe, server default" \
"$P_SRV debug_level=3" \
- "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \
+ "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \
0 \
-S "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \
-S "server hello, secure renegotiation extension"
@@ -2231,7 +2371,7 @@
requires_gnutls
run_test "Renego ext: gnutls client unsafe, server break legacy" \
"$P_SRV debug_level=3 allow_legacy=-1" \
- "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \
+ "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \
1 \
-S "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \
-S "server hello, secure renegotiation extension"
@@ -2242,7 +2382,7 @@
run_test "DER format: no trailing bytes" \
"$P_SRV crt_file=data_files/server5-der0.crt \
key_file=data_files/server5.key" \
- "$G_CLI " \
+ "$G_CLI localhost" \
0 \
-c "Handshake was completed" \
@@ -2250,7 +2390,7 @@
run_test "DER format: with a trailing zero byte" \
"$P_SRV crt_file=data_files/server5-der1a.crt \
key_file=data_files/server5.key" \
- "$G_CLI " \
+ "$G_CLI localhost" \
0 \
-c "Handshake was completed" \
@@ -2258,7 +2398,7 @@
run_test "DER format: with a trailing random byte" \
"$P_SRV crt_file=data_files/server5-der1b.crt \
key_file=data_files/server5.key" \
- "$G_CLI " \
+ "$G_CLI localhost" \
0 \
-c "Handshake was completed" \
@@ -2266,7 +2406,7 @@
run_test "DER format: with 2 trailing random bytes" \
"$P_SRV crt_file=data_files/server5-der2.crt \
key_file=data_files/server5.key" \
- "$G_CLI " \
+ "$G_CLI localhost" \
0 \
-c "Handshake was completed" \
@@ -2274,7 +2414,7 @@
run_test "DER format: with 4 trailing random bytes" \
"$P_SRV crt_file=data_files/server5-der4.crt \
key_file=data_files/server5.key" \
- "$G_CLI " \
+ "$G_CLI localhost" \
0 \
-c "Handshake was completed" \
@@ -2282,7 +2422,7 @@
run_test "DER format: with 8 trailing random bytes" \
"$P_SRV crt_file=data_files/server5-der8.crt \
key_file=data_files/server5.key" \
- "$G_CLI " \
+ "$G_CLI localhost" \
0 \
-c "Handshake was completed" \
@@ -2290,7 +2430,7 @@
run_test "DER format: with 9 trailing random bytes" \
"$P_SRV crt_file=data_files/server5-der9.crt \
key_file=data_files/server5.key" \
- "$G_CLI " \
+ "$G_CLI localhost" \
0 \
-c "Handshake was completed" \
@@ -3855,14 +3995,14 @@
requires_gnutls
run_test "ClientHello without extensions, SHA-1 allowed" \
"$P_SRV debug_level=3" \
- "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION" \
+ "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \
0 \
-s "dumping 'client hello extensions' (0 bytes)"
requires_gnutls
run_test "ClientHello without extensions, SHA-1 forbidden in certificates on server" \
"$P_SRV debug_level=3 key_file=data_files/server2.key crt_file=data_files/server2.crt allow_sha1=0" \
- "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION" \
+ "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \
0 \
-s "dumping 'client hello extensions' (0 bytes)"
@@ -5037,6 +5177,810 @@
-c "found fragmented DTLS handshake message" \
-C "error"
+# Tests for sending fragmented handshake messages with DTLS
+#
+# Use client auth when we need the client to send large messages,
+# and use large cert chains on both sides too (the long chains we have all use
+# both RSA and ECDSA, but ideally we should have long chains with either).
+# Sizes reached (UDP payload):
+# - 2037B for server certificate
+# - 1542B for client certificate
+# - 1013B for newsessionticket
+# - all others below 512B
+# All those tests assume MAX_CONTENT_LEN is at least 2048
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "DTLS fragmenting: none (for reference)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ max_frag_len=4096" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ max_frag_len=4096" \
+ 0 \
+ -S "found fragmented DTLS handshake message" \
+ -C "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "DTLS fragmenting: server only (max_frag_len)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ max_frag_len=1024" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ max_frag_len=2048" \
+ 0 \
+ -S "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# With the MFL extension, the server has no way of forcing
+# the client to not exceed a certain MTU; hence, the following
+# test can't be replicated with an MTU proxy such as the one
+# `client-initiated, server only (max_frag_len)` below.
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "DTLS fragmenting: server only (more) (max_frag_len)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ max_frag_len=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ max_frag_len=4096" \
+ 0 \
+ -S "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "DTLS fragmenting: client-initiated, server only (max_frag_len)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=none \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ max_frag_len=2048" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ max_frag_len=512" \
+ 0 \
+ -S "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# While not required by the standard defining the MFL extension
+# (according to which it only applies to records, not to datagrams),
+# Mbed TLS will never send datagrams larger than MFL + { Max record expansion },
+# as otherwise there wouldn't be any means to communicate MTU restrictions
+# to the peer.
+# The next test checks that no datagrams significantly larger than the
+# negotiated MFL are sent.
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "DTLS fragmenting: client-initiated, server only (max_frag_len), proxy MTU" \
+ -p "$P_PXY mtu=560" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=none \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ max_frag_len=2048" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ max_frag_len=512" \
+ 0 \
+ -S "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "DTLS fragmenting: client-initiated, both (max_frag_len)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ max_frag_len=2048" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ max_frag_len=512" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# While not required by the standard defining the MFL extension
+# (according to which it only applies to records, not to datagrams),
+# Mbed TLS will never send datagrams larger than MFL + { Max record expansion },
+# as otherwise there wouldn't be any means to communicate MTU restrictions
+# to the peer.
+# The next test checks that no datagrams significantly larger than the
+# negotiated MFL are sent.
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test "DTLS fragmenting: client-initiated, both (max_frag_len), proxy MTU" \
+ -p "$P_PXY mtu=560" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ max_frag_len=2048" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ max_frag_len=512" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: none (for reference) (MTU)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=4096" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=4096" \
+ 0 \
+ -S "found fragmented DTLS handshake message" \
+ -C "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: client (MTU)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=4096" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -C "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: server (MTU)" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=2048" \
+ 0 \
+ -S "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: both (MTU)" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# Test for automatic MTU reduction on repeated resend
+not_with_valgrind
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: proxy MTU: auto-reduction" \
+ -p "$P_PXY mtu=508" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key\
+ hs_timeout=100-400" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=100-400" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+only_with_valgrind
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: proxy MTU: auto-reduction" \
+ -p "$P_PXY mtu=508" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key\
+ hs_timeout=250-10000" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=250-10000" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# the proxy shouldn't drop or mess up anything, so we shouldn't need to resend
+# OTOH the client might resend if the server is to slow to reset after sending
+# a HelloVerifyRequest, so only check for no retransmission server-side
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: proxy MTU, simple handshake" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: proxy MTU, simple handshake, nbio" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512 nbio=2" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512 nbio=2" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# This ensures things still work after session_reset().
+# It also exercises the "resumed handshake" flow.
+# Since we don't support reading fragmented ClientHello yet,
+# up the MTU to 1450 (larger than ClientHello with session ticket,
+# but still smaller than client's Certificate to ensure fragmentation).
+# A resend on the client-side might happen if the server is
+# slow to reset, therefore omitting '-C "resend"' below.
+# reco_delay avoids races where the client reconnects before the server has
+# resumed listening, which would result in a spurious resend.
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+run_test "DTLS fragmenting: proxy MTU, resumed handshake" \
+ -p "$P_PXY mtu=1450" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=1450" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=1450 reconnect=1 reco_delay=1" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# A resend on the client-side might happen if the server is
+# slow to reset, therefore omitting '-C "resend"' below.
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SHA256_C
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+requires_config_enabled MBEDTLS_CHACHAPOLY_C
+run_test "DTLS fragmenting: proxy MTU, ChachaPoly renego" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ exchanges=2 renegotiation=1 \
+ force_ciphersuite=TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256 \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ exchanges=2 renegotiation=1 renegotiate=1 \
+ mtu=512" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# A resend on the client-side might happen if the server is
+# slow to reset, therefore omitting '-C "resend"' below.
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SHA256_C
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+requires_config_enabled MBEDTLS_AES_C
+requires_config_enabled MBEDTLS_GCM_C
+run_test "DTLS fragmenting: proxy MTU, AES-GCM renego" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ exchanges=2 renegotiation=1 \
+ force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256 \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ exchanges=2 renegotiation=1 renegotiate=1 \
+ mtu=512" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# A resend on the client-side might happen if the server is
+# slow to reset, therefore omitting '-C "resend"' below.
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SHA256_C
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+requires_config_enabled MBEDTLS_AES_C
+requires_config_enabled MBEDTLS_CCM_C
+run_test "DTLS fragmenting: proxy MTU, AES-CCM renego" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ exchanges=2 renegotiation=1 \
+ force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8 \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ exchanges=2 renegotiation=1 renegotiate=1 \
+ mtu=512" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# A resend on the client-side might happen if the server is
+# slow to reset, therefore omitting '-C "resend"' below.
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SHA256_C
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+requires_config_enabled MBEDTLS_AES_C
+requires_config_enabled MBEDTLS_CIPHER_MODE_CBC
+requires_config_enabled MBEDTLS_SSL_ENCRYPT_THEN_MAC
+run_test "DTLS fragmenting: proxy MTU, AES-CBC EtM renego" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ exchanges=2 renegotiation=1 \
+ force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ exchanges=2 renegotiation=1 renegotiate=1 \
+ mtu=512" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# A resend on the client-side might happen if the server is
+# slow to reset, therefore omitting '-C "resend"' below.
+not_with_valgrind # spurious resend due to timeout
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SHA256_C
+requires_config_enabled MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA
+requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
+requires_config_enabled MBEDTLS_AES_C
+requires_config_enabled MBEDTLS_CIPHER_MODE_CBC
+run_test "DTLS fragmenting: proxy MTU, AES-CBC non-EtM renego" \
+ -p "$P_PXY mtu=512" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ exchanges=2 renegotiation=1 \
+ force_ciphersuite=TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256 etm=0 \
+ mtu=512" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ exchanges=2 renegotiation=1 renegotiate=1 \
+ mtu=512" \
+ 0 \
+ -S "resend" \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+client_needs_more_time 2
+run_test "DTLS fragmenting: proxy MTU + 3d" \
+ -p "$P_PXY mtu=512 drop=8 delay=8 duplicate=8" \
+ "$P_SRV dgram_packing=0 dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ hs_timeout=250-10000 mtu=512" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=250-10000 mtu=512" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+client_needs_more_time 2
+run_test "DTLS fragmenting: proxy MTU + 3d, nbio" \
+ -p "$P_PXY mtu=512 drop=8 delay=8 duplicate=8" \
+ "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ hs_timeout=250-10000 mtu=512 nbio=2" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=250-10000 mtu=512 nbio=2" \
+ 0 \
+ -s "found fragmented DTLS handshake message" \
+ -c "found fragmented DTLS handshake message" \
+ -C "error"
+
+# interop tests for DTLS fragmentating with reliable connection
+#
+# here and below we just want to test that the we fragment in a way that
+# pleases other implementations, so we don't need the peer to fragment
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_gnutls
+run_test "DTLS fragmenting: gnutls server, DTLS 1.2" \
+ "$G_SRV -u" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512 force_version=dtls1_2" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+requires_gnutls
+run_test "DTLS fragmenting: gnutls server, DTLS 1.0" \
+ "$G_SRV -u" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512 force_version=dtls1" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+# We use --insecure for the GnuTLS client because it expects
+# the hostname / IP it connects to to be the name used in the
+# certificate obtained from the server. Here, however, it
+# connects to 127.0.0.1 while our test certificates use 'localhost'
+# as the server name in the certificate. This will make the
+# certifiate validation fail, but passing --insecure makes
+# GnuTLS continue the connection nonetheless.
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+requires_gnutls
+run_test "DTLS fragmenting: gnutls client, DTLS 1.2" \
+ "$P_SRV dtls=1 debug_level=2 \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512 force_version=dtls1_2" \
+ "$G_CLI -u --insecure 127.0.0.1" \
+ 0 \
+ -s "fragmenting handshake message"
+
+# See previous test for the reason to use --insecure
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+requires_gnutls
+run_test "DTLS fragmenting: gnutls client, DTLS 1.0" \
+ "$P_SRV dtls=1 debug_level=2 \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512 force_version=dtls1" \
+ "$G_CLI -u --insecure 127.0.0.1" \
+ 0 \
+ -s "fragmenting handshake message"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test "DTLS fragmenting: openssl server, DTLS 1.2" \
+ "$O_SRV -dtls1_2 -verify 10" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512 force_version=dtls1_2" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+run_test "DTLS fragmenting: openssl server, DTLS 1.0" \
+ "$O_SRV -dtls1 -verify 10" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ mtu=512 force_version=dtls1" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+run_test "DTLS fragmenting: openssl client, DTLS 1.2" \
+ "$P_SRV dtls=1 debug_level=2 \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512 force_version=dtls1_2" \
+ "$O_CLI -dtls1_2" \
+ 0 \
+ -s "fragmenting handshake message"
+
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+run_test "DTLS fragmenting: openssl client, DTLS 1.0" \
+ "$P_SRV dtls=1 debug_level=2 \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ mtu=512 force_version=dtls1" \
+ "$O_CLI -dtls1" \
+ 0 \
+ -s "fragmenting handshake message"
+
+# interop tests for DTLS fragmentating with unreliable connection
+#
+# again we just want to test that the we fragment in a way that
+# pleases other implementations, so we don't need the peer to fragment
+requires_gnutls_next
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+client_needs_more_time 4
+run_test "DTLS fragmenting: 3d, gnutls server, DTLS 1.2" \
+ -p "$P_PXY drop=8 delay=8 duplicate=8" \
+ "$G_NEXT_SRV -u" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+requires_gnutls_next
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+client_needs_more_time 4
+run_test "DTLS fragmenting: 3d, gnutls server, DTLS 1.0" \
+ -p "$P_PXY drop=8 delay=8 duplicate=8" \
+ "$G_NEXT_SRV -u" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=250-60000 mtu=512 force_version=dtls1" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+## The two tests below are disabled due to a bug in GnuTLS client that causes
+## handshake failures when the NewSessionTicket message is lost, see
+## https://gitlab.com/gnutls/gnutls/issues/543
+## We can re-enable them when a fixed version fo GnuTLS is available
+## and installed in our CI system.
+skip_next_test
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+client_needs_more_time 4
+run_test "DTLS fragmenting: 3d, gnutls client, DTLS 1.2" \
+ -p "$P_PXY drop=8 delay=8 duplicate=8" \
+ "$P_SRV dtls=1 debug_level=2 \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
+ "$G_CLI -u --insecure 127.0.0.1" \
+ 0 \
+ -s "fragmenting handshake message"
+
+skip_next_test
+requires_gnutls
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+client_needs_more_time 4
+run_test "DTLS fragmenting: 3d, gnutls client, DTLS 1.0" \
+ -p "$P_PXY drop=8 delay=8 duplicate=8" \
+ "$P_SRV dtls=1 debug_level=2 \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ hs_timeout=250-60000 mtu=512 force_version=dtls1" \
+ "$G_CLI -u --insecure 127.0.0.1" \
+ 0 \
+ -s "fragmenting handshake message"
+
+## Interop test with OpenSSL might triger a bug in recent versions (that
+## probably won't be fixed before 1.1.1X), so we use an old version that
+## doesn't have this bug, but unfortunately it doesn't have support for DTLS
+## 1.2 either, so the DTLS 1.2 tests are commented for now.
+## Bug report: https://github.com/openssl/openssl/issues/6902
+## They should be re-enabled (and the DTLS 1.0 switched back to a non-legacy
+## version of OpenSSL once a fixed version of OpenSSL is available)
+skip_next_test
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+client_needs_more_time 4
+run_test "DTLS fragmenting: 3d, openssl server, DTLS 1.2" \
+ -p "$P_PXY drop=8 delay=8 duplicate=8" \
+ "$O_SRV -dtls1_2 -verify 10" \
+ "$P_CLI dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+requires_openssl_legacy
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+client_needs_more_time 4
+run_test "DTLS fragmenting: 3d, openssl server, DTLS 1.0" \
+ -p "$P_PXY drop=8 delay=8 duplicate=8" \
+ "$O_LEGACY_SRV -dtls1 -verify 10" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
+ crt_file=data_files/server8_int-ca2.crt \
+ key_file=data_files/server8.key \
+ hs_timeout=250-60000 mtu=512 force_version=dtls1" \
+ 0 \
+ -c "fragmenting handshake message" \
+ -C "error"
+
+## see comment on the previous-previous test
+## requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+## requires_config_enabled MBEDTLS_RSA_C
+## requires_config_enabled MBEDTLS_ECDSA_C
+## requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
+## client_needs_more_time 4
+## run_test "DTLS fragmenting: 3d, openssl client, DTLS 1.2" \
+## -p "$P_PXY drop=8 delay=8 duplicate=8" \
+## "$P_SRV dtls=1 debug_level=2 \
+## crt_file=data_files/server7_int-ca.crt \
+## key_file=data_files/server7.key \
+## hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
+## "$O_CLI -dtls1_2" \
+## 0 \
+## -s "fragmenting handshake message"
+
+# -nbio is added to prevent s_client from blocking in case of duplicated
+# messages at the end of the handshake
+requires_openssl_legacy
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
+client_needs_more_time 4
+run_test "DTLS fragmenting: 3d, openssl client, DTLS 1.0" \
+ -p "$P_PXY drop=8 delay=8 duplicate=8" \
+ "$P_SRV dgram_packing=0 dtls=1 debug_level=2 \
+ crt_file=data_files/server7_int-ca.crt \
+ key_file=data_files/server7.key \
+ hs_timeout=250-60000 mtu=512 force_version=dtls1" \
+ "$O_LEGACY_CLI -nbio -dtls1" \
+ 0 \
+ -s "fragmenting handshake message"
+
# Tests for specific things with "unreliable" UDP connection
not_with_valgrind # spurious resend due to timeout
@@ -5058,8 +6002,8 @@
not_with_valgrind # spurious resend due to timeout
run_test "DTLS proxy: duplicate every packet" \
-p "$P_PXY duplicate=1" \
- "$P_SRV dtls=1 debug_level=2" \
- "$P_CLI dtls=1 debug_level=2" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \
0 \
-c "replayed record" \
-s "replayed record" \
@@ -5071,8 +6015,8 @@
run_test "DTLS proxy: duplicate every packet, server anti-replay off" \
-p "$P_PXY duplicate=1" \
- "$P_SRV dtls=1 debug_level=2 anti_replay=0" \
- "$P_CLI dtls=1 debug_level=2" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=2 anti_replay=0" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \
0 \
-c "replayed record" \
-S "replayed record" \
@@ -5085,24 +6029,24 @@
run_test "DTLS proxy: multiple records in same datagram" \
-p "$P_PXY pack=50" \
- "$P_SRV dtls=1 debug_level=2" \
- "$P_CLI dtls=1 debug_level=2" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \
0 \
-c "next record in same datagram" \
-s "next record in same datagram"
run_test "DTLS proxy: multiple records in same datagram, duplicate every packet" \
-p "$P_PXY pack=50 duplicate=1" \
- "$P_SRV dtls=1 debug_level=2" \
- "$P_CLI dtls=1 debug_level=2" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=2" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=2" \
0 \
-c "next record in same datagram" \
-s "next record in same datagram"
run_test "DTLS proxy: inject invalid AD record, default badmac_limit" \
-p "$P_PXY bad_ad=1" \
- "$P_SRV dtls=1 debug_level=1" \
- "$P_CLI dtls=1 debug_level=1 read_timeout=100" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=1" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=1 read_timeout=100" \
0 \
-c "discarding invalid record (mac)" \
-s "discarding invalid record (mac)" \
@@ -5113,8 +6057,8 @@
run_test "DTLS proxy: inject invalid AD record, badmac_limit 1" \
-p "$P_PXY bad_ad=1" \
- "$P_SRV dtls=1 debug_level=1 badmac_limit=1" \
- "$P_CLI dtls=1 debug_level=1 read_timeout=100" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=1" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=1 read_timeout=100" \
1 \
-C "discarding invalid record (mac)" \
-S "discarding invalid record (mac)" \
@@ -5125,8 +6069,8 @@
run_test "DTLS proxy: inject invalid AD record, badmac_limit 2" \
-p "$P_PXY bad_ad=1" \
- "$P_SRV dtls=1 debug_level=1 badmac_limit=2" \
- "$P_CLI dtls=1 debug_level=1 read_timeout=100" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=2" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=1 read_timeout=100" \
0 \
-c "discarding invalid record (mac)" \
-s "discarding invalid record (mac)" \
@@ -5137,8 +6081,8 @@
run_test "DTLS proxy: inject invalid AD record, badmac_limit 2, exchanges 2"\
-p "$P_PXY bad_ad=1" \
- "$P_SRV dtls=1 debug_level=1 badmac_limit=2 exchanges=2" \
- "$P_CLI dtls=1 debug_level=1 read_timeout=100 exchanges=2" \
+ "$P_SRV dtls=1 dgram_packing=0 debug_level=1 badmac_limit=2 exchanges=2" \
+ "$P_CLI dtls=1 dgram_packing=0 debug_level=1 read_timeout=100 exchanges=2" \
1 \
-c "discarding invalid record (mac)" \
-s "discarding invalid record (mac)" \
@@ -5149,22 +6093,174 @@
run_test "DTLS proxy: delay ChangeCipherSpec" \
-p "$P_PXY delay_ccs=1" \
- "$P_SRV dtls=1 debug_level=1" \
- "$P_CLI dtls=1 debug_level=1" \
+ "$P_SRV dtls=1 debug_level=1 dgram_packing=0" \
+ "$P_CLI dtls=1 debug_level=1 dgram_packing=0" \
0 \
-c "record from another epoch" \
-s "record from another epoch" \
-s "Extra-header:" \
-c "HTTP/1.0 200 OK"
+# Tests for reordering support with DTLS
+
+run_test "DTLS reordering: Buffer out-of-order handshake message on client" \
+ -p "$P_PXY delay_srv=ServerHello" \
+ "$P_SRV dgram_packing=0 cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -c "Buffering HS message" \
+ -c "Next handshake message has been buffered - load"\
+ -S "Buffering HS message" \
+ -S "Next handshake message has been buffered - load"\
+ -C "Injecting buffered CCS message" \
+ -C "Remember CCS message" \
+ -S "Injecting buffered CCS message" \
+ -S "Remember CCS message"
+
+run_test "DTLS reordering: Buffer out-of-order handshake message fragment on client" \
+ -p "$P_PXY delay_srv=ServerHello" \
+ "$P_SRV mtu=512 dgram_packing=0 cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -c "Buffering HS message" \
+ -c "found fragmented DTLS handshake message"\
+ -c "Next handshake message 1 not or only partially bufffered" \
+ -c "Next handshake message has been buffered - load"\
+ -S "Buffering HS message" \
+ -S "Next handshake message has been buffered - load"\
+ -C "Injecting buffered CCS message" \
+ -C "Remember CCS message" \
+ -S "Injecting buffered CCS message" \
+ -S "Remember CCS message"
+
+# The client buffers the ServerKeyExchange before receiving the fragmented
+# Certificate message; at the time of writing, together these are aroudn 1200b
+# in size, so that the bound below ensures that the certificate can be reassembled
+# while keeping the ServerKeyExchange.
+requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 1300
+run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling next" \
+ -p "$P_PXY delay_srv=Certificate delay_srv=Certificate" \
+ "$P_SRV mtu=512 dgram_packing=0 cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -c "Buffering HS message" \
+ -c "Next handshake message has been buffered - load"\
+ -C "attempt to make space by freeing buffered messages" \
+ -S "Buffering HS message" \
+ -S "Next handshake message has been buffered - load"\
+ -C "Injecting buffered CCS message" \
+ -C "Remember CCS message" \
+ -S "Injecting buffered CCS message" \
+ -S "Remember CCS message"
+
+# The size constraints ensure that the delayed certificate message can't
+# be reassembled while keeping the ServerKeyExchange message, but it can
+# when dropping it first.
+requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 900
+requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 1299
+run_test "DTLS reordering: Buffer out-of-order hs msg before reassembling next, free buffered msg" \
+ -p "$P_PXY delay_srv=Certificate delay_srv=Certificate" \
+ "$P_SRV mtu=512 dgram_packing=0 cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -c "Buffering HS message" \
+ -c "attempt to make space by freeing buffered future messages" \
+ -c "Enough space available after freeing buffered HS messages" \
+ -S "Buffering HS message" \
+ -S "Next handshake message has been buffered - load"\
+ -C "Injecting buffered CCS message" \
+ -C "Remember CCS message" \
+ -S "Injecting buffered CCS message" \
+ -S "Remember CCS message"
+
+run_test "DTLS reordering: Buffer out-of-order handshake message on server" \
+ -p "$P_PXY delay_cli=Certificate" \
+ "$P_SRV dgram_packing=0 auth_mode=required cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -C "Buffering HS message" \
+ -C "Next handshake message has been buffered - load"\
+ -s "Buffering HS message" \
+ -s "Next handshake message has been buffered - load" \
+ -C "Injecting buffered CCS message" \
+ -C "Remember CCS message" \
+ -S "Injecting buffered CCS message" \
+ -S "Remember CCS message"
+
+run_test "DTLS reordering: Buffer out-of-order CCS message on client"\
+ -p "$P_PXY delay_srv=NewSessionTicket" \
+ "$P_SRV dgram_packing=0 cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -C "Buffering HS message" \
+ -C "Next handshake message has been buffered - load"\
+ -S "Buffering HS message" \
+ -S "Next handshake message has been buffered - load" \
+ -c "Injecting buffered CCS message" \
+ -c "Remember CCS message" \
+ -S "Injecting buffered CCS message" \
+ -S "Remember CCS message"
+
+run_test "DTLS reordering: Buffer out-of-order CCS message on server"\
+ -p "$P_PXY delay_cli=ClientKeyExchange" \
+ "$P_SRV dgram_packing=0 cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -C "Buffering HS message" \
+ -C "Next handshake message has been buffered - load"\
+ -S "Buffering HS message" \
+ -S "Next handshake message has been buffered - load" \
+ -C "Injecting buffered CCS message" \
+ -C "Remember CCS message" \
+ -s "Injecting buffered CCS message" \
+ -s "Remember CCS message"
+
+run_test "DTLS reordering: Buffer encrypted Finished message" \
+ -p "$P_PXY delay_ccs=1" \
+ "$P_SRV dgram_packing=0 cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2" \
+ 0 \
+ -s "Buffer record from epoch 1" \
+ -s "Found buffered record from current epoch - load" \
+ -c "Buffer record from epoch 1" \
+ -c "Found buffered record from current epoch - load"
+
+# In this test, both the fragmented NewSessionTicket and the ChangeCipherSpec
+# from the server are delayed, so that the encrypted Finished message
+# is received and buffered. When the fragmented NewSessionTicket comes
+# in afterwards, the encrypted Finished message must be freed in order
+# to make space for the NewSessionTicket to be reassembled.
+# This works only in very particular circumstances:
+# - MBEDTLS_SSL_DTLS_MAX_BUFFERING must be large enough to allow buffering
+# of the NewSessionTicket, but small enough to also allow buffering of
+# the encrypted Finished message.
+# - The MTU setting on the server must be so small that the NewSessionTicket
+# needs to be fragmented.
+# - All messages sent by the server must be small enough to be either sent
+# without fragmentation or be reassembled within the bounds of
+# MBEDTLS_SSL_DTLS_MAX_BUFFERING. Achieve this by testing with a PSK-based
+# handshake, omitting CRTs.
+requires_config_value_at_least "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 240
+requires_config_value_at_most "MBEDTLS_SSL_DTLS_MAX_BUFFERING" 280
+run_test "DTLS reordering: Buffer encrypted Finished message, drop for fragmented NewSessionTicket" \
+ -p "$P_PXY delay_srv=NewSessionTicket delay_srv=NewSessionTicket delay_ccs=1" \
+ "$P_SRV mtu=190 dgram_packing=0 psk=abc123 psk_identity=foo cookies=0 dtls=1 debug_level=2" \
+ "$P_CLI dgram_packing=0 dtls=1 debug_level=2 force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8 psk=abc123 psk_identity=foo" \
+ 0 \
+ -s "Buffer record from epoch 1" \
+ -s "Found buffered record from current epoch - load" \
+ -c "Buffer record from epoch 1" \
+ -C "Found buffered record from current epoch - load" \
+ -c "Enough space available after freeing future epoch record"
+
# Tests for "randomly unreliable connection": try a variety of flows and peers
client_needs_more_time 2
run_test "DTLS proxy: 3d (drop, delay, duplicate), \"short\" PSK handshake" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none \
psk=abc123" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 psk=abc123 \
force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
0 \
-s "Extra-header:" \
@@ -5173,8 +6269,8 @@
client_needs_more_time 2
run_test "DTLS proxy: 3d, \"short\" RSA handshake" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none" \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 \
force_ciphersuite=TLS-RSA-WITH-AES-128-CBC-SHA" \
0 \
-s "Extra-header:" \
@@ -5183,8 +6279,8 @@
client_needs_more_time 2
run_test "DTLS proxy: 3d, \"short\" (no ticket, no cli_auth) FS handshake" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0" \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none" \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0" \
0 \
-s "Extra-header:" \
-c "HTTP/1.0 200 OK"
@@ -5192,8 +6288,8 @@
client_needs_more_time 2
run_test "DTLS proxy: 3d, FS, client auth" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=required" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0" \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=required" \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0" \
0 \
-s "Extra-header:" \
-c "HTTP/1.0 200 OK"
@@ -5201,8 +6297,8 @@
client_needs_more_time 2
run_test "DTLS proxy: 3d, FS, ticket" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=1 auth_mode=none" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=1" \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=1 auth_mode=none" \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=1" \
0 \
-s "Extra-header:" \
-c "HTTP/1.0 200 OK"
@@ -5210,8 +6306,8 @@
client_needs_more_time 2
run_test "DTLS proxy: 3d, max handshake (FS, ticket + client auth)" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=1 auth_mode=required" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=1" \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=1 auth_mode=required" \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=1" \
0 \
-s "Extra-header:" \
-c "HTTP/1.0 200 OK"
@@ -5219,9 +6315,9 @@
client_needs_more_time 2
run_test "DTLS proxy: 3d, max handshake, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 nbio=2 tickets=1 \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 nbio=2 tickets=1 \
auth_mode=required" \
- "$P_CLI dtls=1 hs_timeout=250-10000 nbio=2 tickets=1" \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 nbio=2 tickets=1" \
0 \
-s "Extra-header:" \
-c "HTTP/1.0 200 OK"
@@ -5229,9 +6325,9 @@
client_needs_more_time 4
run_test "DTLS proxy: 3d, min handshake, resumption" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none \
psk=abc123 debug_level=3" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 psk=abc123 \
debug_level=3 reconnect=1 read_timeout=1000 max_resend=10 \
force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
0 \
@@ -5243,9 +6339,9 @@
client_needs_more_time 4
run_test "DTLS proxy: 3d, min handshake, resumption, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none \
psk=abc123 debug_level=3 nbio=2" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 psk=abc123 \
debug_level=3 reconnect=1 read_timeout=1000 max_resend=10 \
force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8 nbio=2" \
0 \
@@ -5258,9 +6354,9 @@
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
run_test "DTLS proxy: 3d, min handshake, client-initiated renego" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none \
psk=abc123 renegotiation=1 debug_level=2" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 psk=abc123 \
renegotiate=1 debug_level=2 \
force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
0 \
@@ -5273,9 +6369,9 @@
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
run_test "DTLS proxy: 3d, min handshake, client-initiated renego, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none \
psk=abc123 renegotiation=1 debug_level=2" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 psk=abc123 \
renegotiate=1 debug_level=2 \
force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
0 \
@@ -5288,10 +6384,10 @@
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
run_test "DTLS proxy: 3d, min handshake, server-initiated renego" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none \
psk=abc123 renegotiate=1 renegotiation=1 exchanges=4 \
debug_level=2" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 psk=abc123 \
renegotiation=1 exchanges=4 debug_level=2 \
force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
0 \
@@ -5304,10 +6400,10 @@
requires_config_enabled MBEDTLS_SSL_RENEGOTIATION
run_test "DTLS proxy: 3d, min handshake, server-initiated renego, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
- "$P_SRV dtls=1 hs_timeout=250-10000 tickets=0 auth_mode=none \
+ "$P_SRV dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 auth_mode=none \
psk=abc123 renegotiate=1 renegotiation=1 exchanges=4 \
debug_level=2 nbio=2" \
- "$P_CLI dtls=1 hs_timeout=250-10000 tickets=0 psk=abc123 \
+ "$P_CLI dtls=1 dgram_packing=0 hs_timeout=250-10000 tickets=0 psk=abc123 \
renegotiation=1 exchanges=4 debug_level=2 nbio=2 \
force_ciphersuite=TLS-PSK-WITH-AES-128-CCM-8" \
0 \
@@ -5321,7 +6417,7 @@
run_test "DTLS proxy: 3d, openssl server" \
-p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
"$O_SRV -dtls1 -mtu 2048" \
- "$P_CLI dtls=1 hs_timeout=250-60000 tickets=0" \
+ "$P_CLI dgram_packing=0 dtls=1 hs_timeout=250-60000 tickets=0" \
0 \
-c "HTTP/1.0 200 OK"
@@ -5330,7 +6426,7 @@
run_test "DTLS proxy: 3d, openssl server, fragmentation" \
-p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
"$O_SRV -dtls1 -mtu 768" \
- "$P_CLI dtls=1 hs_timeout=250-60000 tickets=0" \
+ "$P_CLI dgram_packing=0 dtls=1 hs_timeout=250-60000 tickets=0" \
0 \
-c "HTTP/1.0 200 OK"
@@ -5339,7 +6435,7 @@
run_test "DTLS proxy: 3d, openssl server, fragmentation, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5 protect_hvr=1" \
"$O_SRV -dtls1 -mtu 768" \
- "$P_CLI dtls=1 hs_timeout=250-60000 nbio=2 tickets=0" \
+ "$P_CLI dgram_packing=0 dtls=1 hs_timeout=250-60000 nbio=2 tickets=0" \
0 \
-c "HTTP/1.0 200 OK"
@@ -5349,7 +6445,7 @@
run_test "DTLS proxy: 3d, gnutls server" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$G_SRV -u --mtu 2048 -a" \
- "$P_CLI dtls=1 hs_timeout=250-60000" \
+ "$P_CLI dgram_packing=0 dtls=1 hs_timeout=250-60000" \
0 \
-s "Extra-header:" \
-c "Extra-header:"
@@ -5360,7 +6456,7 @@
run_test "DTLS proxy: 3d, gnutls server, fragmentation" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$G_SRV -u --mtu 512" \
- "$P_CLI dtls=1 hs_timeout=250-60000" \
+ "$P_CLI dgram_packing=0 dtls=1 hs_timeout=250-60000" \
0 \
-s "Extra-header:" \
-c "Extra-header:"
@@ -5371,7 +6467,7 @@
run_test "DTLS proxy: 3d, gnutls server, fragmentation, nbio" \
-p "$P_PXY drop=5 delay=5 duplicate=5" \
"$G_SRV -u --mtu 512" \
- "$P_CLI dtls=1 hs_timeout=250-60000 nbio=2" \
+ "$P_CLI dgram_packing=0 dtls=1 hs_timeout=250-60000 nbio=2" \
0 \
-s "Extra-header:" \
-c "Extra-header:"
diff --git a/tests/suites/test_suite_nist_kw.data b/tests/suites/test_suite_nist_kw.data
index eee4574..4462558 100644
--- a/tests/suites/test_suite_nist_kw.data
+++ b/tests/suites/test_suite_nist_kw.data
@@ -69,6 +69,27 @@
NIST KW lengths #16 KWP unwrapping output buffer too short
nist_kw_ciphertext_lengths:24:12:MBEDTLS_KW_MODE_KWP:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+NIST KW lengths #17 KW plaintext NULL (2 to 2^54 - 1 semiblocks)
+nist_kw_plaintext_lengths:0:8:MBEDTLS_KW_MODE_KW:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+
+NIST KW lengths #18 KW wrapping output NULL
+nist_kw_plaintext_lengths:8:0:MBEDTLS_KW_MODE_KW:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+
+NIST KW lengths #19 KWP wrapping output NULL
+nist_kw_plaintext_lengths:8:0:MBEDTLS_KW_MODE_KWP:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+
+NIST KW lengths #20 KW ciphertext NULL
+nist_kw_ciphertext_lengths:0:8:MBEDTLS_KW_MODE_KW:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+
+NIST KW lengths #21 KWP ciphertext NULL
+nist_kw_ciphertext_lengths:0:8:MBEDTLS_KW_MODE_KWP:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+
+NIST KW lengths #15 KW unwrapping output NULL
+nist_kw_ciphertext_lengths:32:0:MBEDTLS_KW_MODE_KW:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+
+NIST KW lengths #16 KWP unwrapping output NULL
+nist_kw_ciphertext_lengths:24:0:MBEDTLS_KW_MODE_KWP:MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
+
NIST KW wrap AES-128 CAVS 17.4 PLAINTEXT LENGTH = 128 count 7
depends_on:MBEDTLS_AES_C
mbedtls_nist_kw_wrap:MBEDTLS_CIPHER_ID_AES:MBEDTLS_KW_MODE_KW:"095e293f31e317ba6861114b95c90792":"64349d506ae85ecd84459c7a5c423f55":"97de4425572274bd7fb2d6688d5afd4454d992348d42a643"
diff --git a/tests/suites/test_suite_nist_kw.function b/tests/suites/test_suite_nist_kw.function
index eb67c03..ae3ef80 100644
--- a/tests/suites/test_suite_nist_kw.function
+++ b/tests/suites/test_suite_nist_kw.function
@@ -158,19 +158,17 @@
memset( key, 0, sizeof( key ) );
- if (in_len == 0)
- {
- /* mbedtls_calloc can return NULL for zero-length buffers. Make sure we
- * always have a plaintext buffer, even if the length is 0. */
- plaintext = mbedtls_calloc( 1, 1 );
- }
- else
+ if( in_len != 0 )
{
plaintext = mbedtls_calloc( 1, in_len );
+ TEST_ASSERT( plaintext != NULL );
}
- TEST_ASSERT( plaintext != NULL );
- ciphertext = mbedtls_calloc( 1, output_len );
- TEST_ASSERT( ciphertext != NULL );
+
+ if( out_len != 0 )
+ {
+ ciphertext = mbedtls_calloc( 1, output_len );
+ TEST_ASSERT( ciphertext != NULL );
+ }
memset( plaintext, 0, in_len );
memset( ciphertext, 0, output_len );
@@ -216,10 +214,16 @@
memset( key, 0, sizeof( key ) );
- plaintext = mbedtls_calloc( 1, output_len );
- TEST_ASSERT( plaintext != NULL );
- ciphertext = mbedtls_calloc( 1, in_len );
- TEST_ASSERT( ciphertext != NULL );
+ if( out_len != 0 )
+ {
+ plaintext = mbedtls_calloc( 1, output_len );
+ TEST_ASSERT( plaintext != NULL );
+ }
+ if( in_len != 0 )
+ {
+ ciphertext = mbedtls_calloc( 1, in_len );
+ TEST_ASSERT( ciphertext != NULL );
+ }
memset( plaintext, 0, output_len );
memset( ciphertext, 0, in_len );
diff --git a/tests/suites/test_suite_version.data b/tests/suites/test_suite_version.data
index 402c8b8..c3542e5 100644
--- a/tests/suites/test_suite_version.data
+++ b/tests/suites/test_suite_version.data
@@ -1,8 +1,8 @@
Check compiletime library version
-check_compiletime_version:"2.12.0"
+check_compiletime_version:"2.13.1"
Check runtime library version
-check_runtime_version:"2.12.0"
+check_runtime_version:"2.13.1"
Check for MBEDTLS_VERSION_C
check_feature:"MBEDTLS_VERSION_C":0