Merge pull request #5426 from gilles-peskine-arm/ssl-get-version-3.1

Add accessors to mbedtls_ssl_context: user data, version
ABI-API-checking fails which was expected as this PR adds a new field in mbedtls_ssl_context and mbedtls_ssl_config.
diff --git a/ChangeLog.d/ssl_context-user_data.txt b/ChangeLog.d/ssl_context-user_data.txt
new file mode 100644
index 0000000..630d8f0
--- /dev/null
+++ b/ChangeLog.d/ssl_context-user_data.txt
@@ -0,0 +1,6 @@
+Features
+   * The structures mbedtls_ssl_config and mbedtls_ssl_context now store
+     a piece of user data which is reserved for the application. The user
+     data can be either a pointer or an integer.
+   * Add an accessor function to get the configuration associated with
+     an SSL context.
diff --git a/ChangeLog.d/ssl_context-version_number.txt b/ChangeLog.d/ssl_context-version_number.txt
new file mode 100644
index 0000000..b5951d0
--- /dev/null
+++ b/ChangeLog.d/ssl_context-version_number.txt
@@ -0,0 +1,3 @@
+Features
+   * Add a function to access the protocol version from an SSL context in a
+     form that's easy to compare. Fixes #5407.
diff --git a/ChangeLog.d/ssl_get_version_1_3.txt b/ChangeLog.d/ssl_get_version_1_3.txt
new file mode 100644
index 0000000..4436522
--- /dev/null
+++ b/ChangeLog.d/ssl_get_version_1_3.txt
@@ -0,0 +1,2 @@
+Bugfix
+   * Fix mbedtls_ssl_get_version() not reporting TLSv1.3. Fixes #5406.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 7e5fb19..7544f42 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1161,6 +1161,14 @@
 #endif
 };
 
+/** Human-friendly representation of the (D)TLS protocol version. */
+typedef enum
+{
+    MBEDTLS_SSL_VERSION_UNKNOWN, /*!< Context not in use or version not yet negotiated. */
+    MBEDTLS_SSL_VERSION_1_2,     /*!< (D)TLS 1.2 */
+    MBEDTLS_SSL_VERSION_1_3,     /*!< (D)TLS 1.3 */
+} mbedtls_ssl_protocol_version;
+
 /*
  * Identifiers for PRFs used in various versions of TLS.
  */
@@ -1210,6 +1218,18 @@
                                         const unsigned char server_random[32],
                                         mbedtls_tls_prf_types tls_prf_type );
 
+/* A type for storing user data in a library structure.
+ *
+ * The representation of type may change in future versions of the library.
+ * Only the behaviors guaranteed by documented accessor functions are
+ * guaranteed to remain stable.
+ */
+typedef union
+{
+    uintptr_t n;                /* typically a handle to an associated object */
+    void *p;                    /* typically a pointer to extra data */
+} mbedtls_ssl_user_data_t;
+
 /**
  * SSL/TLS configuration to be shared between mbedtls_ssl_context structures.
  */
@@ -1448,6 +1468,13 @@
 #if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C)
     unsigned int MBEDTLS_PRIVATE(dhm_min_bitlen);    /*!< min. bit length of the DHM prime   */
 #endif
+
+    /** User data pointer or handle.
+     *
+     * The library sets this to \p 0 when creating a context and does not
+     * access it afterwards.
+     */
+    mbedtls_ssl_user_data_t MBEDTLS_PRIVATE(user_data);
 };
 
 struct mbedtls_ssl_context
@@ -1669,6 +1696,17 @@
     /** Callback to export key block and master secret                      */
     mbedtls_ssl_export_keys_t *MBEDTLS_PRIVATE(f_export_keys);
     void *MBEDTLS_PRIVATE(p_export_keys);            /*!< context for key export callback    */
+
+    /** User data pointer or handle.
+     *
+     * The library sets this to \p 0 when creating a context and does not
+     * access it afterwards.
+     *
+     * \warning Serializing and restoring an SSL context with
+     *          mbedtls_ssl_context_save() and mbedtls_ssl_context_load()
+     *          does not currently restore the user data.
+     */
+    mbedtls_ssl_user_data_t MBEDTLS_PRIVATE(user_data);
 };
 
 /**
@@ -1837,6 +1875,22 @@
                   void  *p_dbg );
 
 /**
+ * \brief          Return the SSL configuration structure associated
+ *                 with the given SSL context.
+ *
+ * \note           The pointer returned by this function is guaranteed to
+ *                 remain valid until the context is freed.
+ *
+ * \param ssl      The SSL context to query.
+ * \return         Pointer to the SSL configuration associated with \p ssl.
+ */
+static inline const mbedtls_ssl_config *mbedtls_ssl_context_get_config(
+    const mbedtls_ssl_context *ssl )
+{
+    return( ssl->MBEDTLS_PRIVATE( conf ) );
+}
+
+/**
  * \brief          Set the underlying BIO callbacks for write, read and
  *                 read-with-timeout.
  *
@@ -2263,6 +2317,132 @@
                                      mbedtls_ssl_export_keys_t *f_export_keys,
                                      void *p_export_keys );
 
+/** \brief Set the user data in an SSL configuration to a pointer.
+ *
+ * You can retrieve this value later with mbedtls_ssl_conf_get_user_data_p().
+ *
+ * \note The library stores \c p without accessing it. It is the responsibility
+ *       of the caller to ensure that the pointer remains valid.
+ *
+ * \param conf           The SSL configuration context to modify.
+ * \param p              The new value of the user data.
+ */
+static inline void mbedtls_ssl_conf_set_user_data_p(
+    mbedtls_ssl_config *conf,
+    void *p )
+{
+    conf->MBEDTLS_PRIVATE(user_data).p = p;
+}
+
+/** \brief Set the user data in an SSL configuration to an integer.
+ *
+ * You can retrieve this value later with mbedtls_ssl_conf_get_user_data_n().
+ *
+ * \param conf           The SSL configuration context to modify.
+ * \param n              The new value of the user data.
+ */
+static inline void mbedtls_ssl_conf_set_user_data_n(
+    mbedtls_ssl_config *conf,
+    uintptr_t n )
+{
+    conf->MBEDTLS_PRIVATE(user_data).n = n;
+}
+
+/** \brief Retrieve the user data in an SSL configuration as a pointer.
+ *
+ * This is the value last set with mbedtls_ssl_conf_set_user_data_p(), or
+ * \c NULL if mbedtls_ssl_conf_set_user_data_p() has not previously been
+ * called. The value is undefined if mbedtls_ssl_conf_set_user_data_n() has
+ * been called without a subsequent call to mbedtls_ssl_conf_set_user_data_p().
+ *
+ * \param conf           The SSL configuration context to modify.
+ * \return               The current value of the user data.
+ */
+static inline void *mbedtls_ssl_conf_get_user_data_p(
+    mbedtls_ssl_config *conf )
+{
+    return( conf->MBEDTLS_PRIVATE(user_data).p );
+}
+
+/** \brief Retrieve the user data in an SSL configuration as an integer.
+ *
+ * This is the value last set with mbedtls_ssl_conf_set_user_data_n(), or
+ * \c 0 if mbedtls_ssl_conf_set_user_data_n() has not previously been
+ * called. The value is undefined if mbedtls_ssl_conf_set_user_data_p() has
+ * been called without a subsequent call to mbedtls_ssl_conf_set_user_data_n().
+ *
+ * \param conf           The SSL configuration context to modify.
+ * \return               The current value of the user data.
+ */
+static inline uintptr_t mbedtls_ssl_conf_get_user_data_n(
+    mbedtls_ssl_config *conf )
+{
+    return( conf->MBEDTLS_PRIVATE(user_data).n );
+}
+
+/** \brief Set the user data in an SSL context to a pointer.
+ *
+ * You can retrieve this value later with mbedtls_ssl_get_user_data_p().
+ *
+ * \note The library stores \c p without accessing it. It is the responsibility
+ *       of the caller to ensure that the pointer remains valid.
+ *
+ * \param ssl            The SSL context context to modify.
+ * \param p              The new value of the user data.
+ */
+static inline void mbedtls_ssl_set_user_data_p(
+    mbedtls_ssl_context *ssl,
+    void *p )
+{
+    ssl->MBEDTLS_PRIVATE(user_data).p = p;
+}
+
+/** \brief Set the user data in an SSL context to an integer.
+ *
+ * You can retrieve this value later with mbedtls_ssl_get_user_data_n().
+ *
+ * \param ssl            The SSL context context to modify.
+ * \param n              The new value of the user data.
+ */
+static inline void mbedtls_ssl_set_user_data_n(
+    mbedtls_ssl_context *ssl,
+    uintptr_t n )
+{
+    ssl->MBEDTLS_PRIVATE(user_data).n = n;
+}
+
+/** \brief Retrieve the user data in an SSL context as a pointer.
+ *
+ * This is the value last set with mbedtls_ssl_set_user_data_p(), or
+ * \c NULL if mbedtls_ssl_set_user_data_p() has not previously been
+ * called. The value is undefined if mbedtls_ssl_set_user_data_n() has
+ * been called without a subsequent call to mbedtls_ssl_set_user_data_p().
+ *
+ * \param ssl            The SSL context context to modify.
+ * \return               The current value of the user data.
+ */
+static inline void *mbedtls_ssl_get_user_data_p(
+    mbedtls_ssl_context *ssl )
+{
+    return( ssl->MBEDTLS_PRIVATE(user_data).p );
+}
+
+/** \brief Retrieve the user data in an SSL context as an integer.
+ *
+ * This is the value last set with mbedtls_ssl_set_user_data_n(), or
+ * \c 0 if mbedtls_ssl_set_user_data_n() has not previously been
+ * called. The value is undefined if mbedtls_ssl_set_user_data_p() has
+ * been called without a subsequent call to mbedtls_ssl_set_user_data_n().
+ *
+ * \param ssl            The SSL context context to modify.
+ * \return               The current value of the user data.
+ */
+static inline uintptr_t mbedtls_ssl_get_user_data_n(
+    mbedtls_ssl_context *ssl )
+{
+    return( ssl->MBEDTLS_PRIVATE(user_data).n );
+}
+
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
 /**
  * \brief           Configure asynchronous private key operation callbacks.
@@ -3558,31 +3738,50 @@
 
 /**
  * \brief          Set the maximum supported version sent from the client side
- *                 and/or accepted at the server side
- *                 (Default: MBEDTLS_SSL_MAX_MAJOR_VERSION, MBEDTLS_SSL_MAX_MINOR_VERSION)
+ *                 and/or accepted at the server side.
+ *
+ *                 See also the documentation of mbedtls_ssl_conf_min_version().
  *
  * \note           This ignores ciphersuites from higher versions.
  *
- * \note           With DTLS, use MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2
- *
  * \param conf     SSL configuration
- * \param major    Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported)
- * \param minor    Minor version number (only MBEDTLS_SSL_MINOR_VERSION_3 supported)
+ * \param major    Major version number (#MBEDTLS_SSL_MAJOR_VERSION_3)
+ * \param minor    Minor version number
+ *                 (#MBEDTLS_SSL_MINOR_VERSION_3 for (D)TLS 1.2,
+ *                 #MBEDTLS_SSL_MINOR_VERSION_4 for TLS 1.3)
  */
 void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor );
 
 /**
  * \brief          Set the minimum accepted SSL/TLS protocol version
- *                 (Default: TLS 1.2)
+ *
+ * \note           By default, all supported versions are accepted.
+ *                 Future versions of the library may disable older
+ *                 protocol versions by default if they become deprecated.
+ *
+ * \note           The following versions are supported (if enabled at
+ *                 compile time):
+ *                 - (D)TLS 1.2: \p major = #MBEDTLS_SSL_MAJOR_VERSION_3,
+ *                   \p minor = #MBEDTLS_SSL_MINOR_VERSION_3
+ *                 - TLS 1.3: \p major = #MBEDTLS_SSL_MAJOR_VERSION_3,
+ *                   \p minor = #MBEDTLS_SSL_MINOR_VERSION_4
+ *
+ *                 Note that the numbers in the constant names are the
+ *                 TLS internal protocol numbers, and the minor versions
+ *                 differ by one from the human-readable versions!
  *
  * \note           Input outside of the SSL_MAX_XXXXX_VERSION and
  *                 SSL_MIN_XXXXX_VERSION range is ignored.
  *
- * \note           With DTLS, use MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2
+ * \note           After the handshake, you can call
+ *                 mbedtls_ssl_get_version_number() to see what version was
+ *                 negotiated.
  *
  * \param conf     SSL configuration
- * \param major    Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported)
- * \param minor    Minor version number (only MBEDTLS_SSL_MINOR_VERSION_3 supported)
+ * \param major    Major version number (#MBEDTLS_SSL_MAJOR_VERSION_3)
+ * \param minor    Minor version number
+ *                 (#MBEDTLS_SSL_MINOR_VERSION_3 for (D)TLS 1.2,
+ *                 #MBEDTLS_SSL_MINOR_VERSION_4 for TLS 1.3)
  */
 void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor );
 
@@ -3903,6 +4102,21 @@
  */
 const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl );
 
+
+/**
+ * \brief          Return the (D)TLS protocol version negotiated in the
+ *                 given connection.
+ *
+ * \note           If you call this function too early during the initial
+ *                 handshake, before the two sides have agreed on a version,
+ *                 this function returns #MBEDTLS_SSL_VERSION_UNKNOWN.
+ *
+ * \param ssl      The SSL context to query.
+ * \return         The negotiated protocol version.
+ */
+mbedtls_ssl_protocol_version mbedtls_ssl_get_version_number(
+    const mbedtls_ssl_context *ssl );
+
 /**
  * \brief          Return the current TLS version
  *
@@ -4334,6 +4548,14 @@
  *
  * \see            mbedtls_ssl_context_load()
  *
+ * \note           The serialized data only contains the data that is
+ *                 necessary to resume the connection: negotiated protocol
+ *                 options, session identifier, keys, etc.
+ *                 Loading a saved SSL context does not restore settings and
+ *                 state related to how the application accesses the context,
+ *                 such as configured callback functions, user data, pending
+ *                 incoming or outgoing data, etc.
+ *
  * \note           This feature is currently only available under certain
  *                 conditions, see the documentation of the return value
  *                 #MBEDTLS_ERR_SSL_BAD_INPUT_DATA for details.
@@ -4412,8 +4634,11 @@
  *                 (unless they were already set before calling
  *                 mbedtls_ssl_session_reset() and the values are suitable for
  *                 the present connection). Specifically, you want to call
- *                 at least mbedtls_ssl_set_bio() and
- *                 mbedtls_ssl_set_timer_cb(). All other SSL setter functions
+ *                 at least mbedtls_ssl_set_bio(),
+ *                 mbedtls_ssl_set_timer_cb(), and
+ *                 mbedtls_ssl_set_user_data_n() or
+ *                 mbedtls_ssl_set_user_data_p() if they were set originally.
+ *                 All other SSL setter functions
  *                 are not necessary to call, either because they're only used
  *                 in handshakes, or because the setting is already saved. You
  *                 might choose to call them anyway, for example in order to
diff --git a/library/ssl_debug_helpers.h b/library/ssl_debug_helpers.h
index 2fc4163..2ffc5f4 100644
--- a/library/ssl_debug_helpers.h
+++ b/library/ssl_debug_helpers.h
@@ -33,6 +33,8 @@
 
 const char *mbedtls_ssl_states_str( mbedtls_ssl_states in );
 
+const char *mbedtls_ssl_protocol_version_str( mbedtls_ssl_protocol_version in );
+
 const char *mbedtls_tls_prf_types_str( mbedtls_tls_prf_types in );
 
 const char *mbedtls_ssl_key_export_type_str( mbedtls_ssl_key_export_type in );
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index e80adb1..adb18ab 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -2206,6 +2206,21 @@
     return mbedtls_ssl_get_ciphersuite_name( ssl->session->ciphersuite );
 }
 
+mbedtls_ssl_protocol_version mbedtls_ssl_get_version_number(
+    const mbedtls_ssl_context *ssl )
+{
+    /* For major_ver, only 3 is supported, so skip checking it. */
+    switch( ssl->minor_ver )
+    {
+        case MBEDTLS_SSL_MINOR_VERSION_3:
+            return( MBEDTLS_SSL_VERSION_1_2 );
+        case MBEDTLS_SSL_MINOR_VERSION_4:
+            return( MBEDTLS_SSL_VERSION_1_3 );
+        default:
+            return( MBEDTLS_SSL_VERSION_UNKNOWN );
+    }
+}
+
 const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl )
 {
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
@@ -2226,7 +2241,8 @@
     {
         case MBEDTLS_SSL_MINOR_VERSION_3:
             return( "TLSv1.2" );
-
+        case MBEDTLS_SSL_MINOR_VERSION_4:
+            return( "TLSv1.3" );
         default:
             return( "unknown" );
     }
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index dd05716..2fe7a40 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -9668,6 +9668,7 @@
             -c "<= parse certificate verify"          \
             -c "mbedtls_ssl_tls13_process_certificate_verify() returned 0" \
             -c "<= parse finished message" \
+            -c "Protocol is TLSv1.3" \
             -c "HTTP/1.0 200 ok"
 
 requires_gnutls_tls1_3
@@ -9701,6 +9702,7 @@
             -c "<= parse certificate verify"          \
             -c "mbedtls_ssl_tls13_process_certificate_verify() returned 0" \
             -c "<= parse finished message" \
+            -c "Protocol is TLSv1.3" \
             -c "HTTP/1.0 200 OK"
 
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_3
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index cb66f3a..4f5ee97 100644
--- a/tests/suites/test_suite_ssl.function
+++ b/tests/suites/test_suite_ssl.function
@@ -886,6 +886,7 @@
                            mbedtls_test_message_queue *output_queue )
 {
     int ret = -1;
+    uintptr_t user_data_n;
 
     if( dtls_context != NULL && ( input_queue == NULL || output_queue == NULL ) )
         return MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
@@ -904,6 +905,18 @@
         mbedtls_ctr_drbg_random,
         &( ep->ctr_drbg ) );
     mbedtls_entropy_init( &( ep->entropy ) );
+
+    TEST_ASSERT( mbedtls_ssl_conf_get_user_data_p( &ep->conf ) == NULL );
+    TEST_EQUAL( mbedtls_ssl_conf_get_user_data_n( &ep->conf ), 0 );
+    TEST_ASSERT( mbedtls_ssl_get_user_data_p( &ep->ssl ) == NULL );
+    TEST_EQUAL( mbedtls_ssl_get_user_data_n( &ep->ssl ), 0 );
+
+    (void) mbedtls_test_rnd_std_rand( NULL,
+                                      (void*) &user_data_n,
+                                      sizeof( user_data_n ) );
+    mbedtls_ssl_conf_set_user_data_n( &ep->conf, user_data_n );
+    mbedtls_ssl_set_user_data_n( &ep->ssl, user_data_n );
+
     if( dtls_context != NULL )
     {
         TEST_ASSERT( mbedtls_message_socket_setup( input_queue, output_queue,
@@ -954,6 +967,11 @@
     ret = mbedtls_endpoint_certificate_init( ep, pk_alg );
     TEST_ASSERT( ret == 0 );
 
+    TEST_EQUAL( mbedtls_ssl_conf_get_user_data_n( &ep->conf ), user_data_n );
+    mbedtls_ssl_conf_set_user_data_p( &ep->conf, ep );
+    TEST_EQUAL( mbedtls_ssl_get_user_data_n( &ep->ssl ), user_data_n );
+    mbedtls_ssl_set_user_data_p( &ep->ssl, ep );
+
 exit:
     return ret;
 }
@@ -1793,6 +1811,45 @@
                                   ssl_2, 256, 1 );
 }
 
+int check_ssl_version( int expected_negotiated_version,
+                       const mbedtls_ssl_context *ssl )
+{
+    const char *version_string = mbedtls_ssl_get_version( ssl );
+    mbedtls_ssl_protocol_version version_number =
+        mbedtls_ssl_get_version_number( ssl );
+
+    TEST_EQUAL( ssl->major_ver, MBEDTLS_SSL_MAJOR_VERSION_3 );
+    TEST_EQUAL( ssl->minor_ver, expected_negotiated_version );
+
+    if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM )
+    {
+        TEST_EQUAL( version_string[0], 'D' );
+        ++version_string;
+    }
+
+    switch( expected_negotiated_version )
+    {
+        case MBEDTLS_SSL_MINOR_VERSION_3:
+            TEST_EQUAL( version_number, MBEDTLS_SSL_VERSION_1_2 );
+            TEST_ASSERT( strcmp( version_string, "TLSv1.2" ) == 0 );
+            break;
+
+        case MBEDTLS_SSL_MINOR_VERSION_4:
+            TEST_EQUAL( version_number, MBEDTLS_SSL_VERSION_1_3 );
+            TEST_ASSERT( strcmp( version_string, "TLSv1.3" ) == 0 );
+            break;
+
+        default:
+            TEST_ASSERT( ! "Version check not implemented for this protocol version" );
+    }
+
+    return( 1 );
+
+exit:
+    return( 0 );
+}
+
+
 #if defined(MBEDTLS_X509_CRT_PARSE_C) && \
     defined(MBEDTLS_ENTROPY_C) && \
     defined(MBEDTLS_CTR_DRBG_C)
@@ -1984,11 +2041,16 @@
     TEST_ASSERT( client.ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER );
     TEST_ASSERT( server.ssl.state == MBEDTLS_SSL_HANDSHAKE_OVER );
 
-    /* Check that we agree on the version... */
-    TEST_ASSERT( client.ssl.minor_ver == server.ssl.minor_ver );
+    /* Check that both sides have negotiated the expected version. */
+    mbedtls_test_set_step( 0 );
+    if( ! check_ssl_version( options->expected_negotiated_version,
+                             &client.ssl ) )
+        goto exit;
 
-    /* And check that the version negotiated is the expected one. */
-    TEST_EQUAL( client.ssl.minor_ver, options->expected_negotiated_version );
+    mbedtls_test_set_step( 1 );
+    if( ! check_ssl_version( options->expected_negotiated_version,
+                             &server.ssl ) )
+        goto exit;
 
 #if defined(MBEDTLS_SSL_VARIABLE_BUFFER_LENGTH)
     if( options->resize_buffers != 0 )
@@ -2043,6 +2105,8 @@
                              mbedtls_mock_tcp_recv_msg,
                              NULL );
 
+        mbedtls_ssl_set_user_data_p( &server.ssl, &server );
+
 #if defined(MBEDTLS_TIMING_C)
         mbedtls_ssl_set_timer_cb( &server.ssl, &timer_server,
                                   mbedtls_timing_set_delay,
@@ -2150,6 +2214,11 @@
     }
 #endif /* MBEDTLS_SSL_RENEGOTIATION */
 
+    TEST_ASSERT( mbedtls_ssl_conf_get_user_data_p( &client.conf ) == &client );
+    TEST_ASSERT( mbedtls_ssl_get_user_data_p( &client.ssl ) == &client );
+    TEST_ASSERT( mbedtls_ssl_conf_get_user_data_p( &server.conf ) == &server );
+    TEST_ASSERT( mbedtls_ssl_get_user_data_p( &server.ssl ) == &server );
+
 exit:
     mbedtls_endpoint_free( &client, options->dtls != 0 ? &client_context : NULL );
     mbedtls_endpoint_free( &server, options->dtls != 0 ? &server_context : NULL );