Make user_data fields private

Add accessor functions.

Add unit tests for the accessor functions.

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/ChangeLog.d/ssl_context-user_data.txt b/ChangeLog.d/ssl_context-user_data.txt
index 1198847..630d8f0 100644
--- a/ChangeLog.d/ssl_context-user_data.txt
+++ b/ChangeLog.d/ssl_context-user_data.txt
@@ -1,5 +1,6 @@
 Features
-   * The structures mbedtls_ssl_config and mbedtls_ssl_context have an
-     extra field user_data which is reserved for the application.
+   * 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/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index d911b8f..a96b5c8 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1462,7 +1462,7 @@
      * The library sets this to \p 0 when creating a context and does not
      * access it afterwards.
      */
-    uintptr_t user_data;
+    uintptr_t MBEDTLS_PRIVATE(user_data);
 };
 
 struct mbedtls_ssl_context
@@ -1690,7 +1690,7 @@
      * The library sets this to \p 0 when creating a context and does not
      * access it afterwards.
      */
-    uintptr_t user_data;
+    uintptr_t MBEDTLS_PRIVATE(user_data);
 };
 
 /**
@@ -2301,6 +2301,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) = (uintptr_t) 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;
+}
+
+/** \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_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 void *mbedtls_ssl_conf_get_user_data_p(
+    mbedtls_ssl_config *conf )
+{
+    return( (void*) conf->MBEDTLS_PRIVATE(user_data) );
+}
+
+/** \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_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 uintptr_t mbedtls_ssl_conf_get_user_data_n(
+    mbedtls_ssl_config *conf )
+{
+    return( conf->MBEDTLS_PRIVATE(user_data) );
+}
+
+/** \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) = (uintptr_t) 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;
+}
+
+/** \brief Retrieve the user data in an SSL context as a pointer.
+ *
+ * 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 void *mbedtls_ssl_get_user_data_p(
+    mbedtls_ssl_context *ssl )
+{
+    return( (void*) ssl->MBEDTLS_PRIVATE(user_data) );
+}
+
+/** \brief Retrieve the user data in an SSL context as an integer.
+ *
+ * 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 uintptr_t mbedtls_ssl_get_user_data_n(
+    mbedtls_ssl_context *ssl )
+{
+    return( ssl->MBEDTLS_PRIVATE(user_data) );
+}
+
 #if defined(MBEDTLS_SSL_ASYNC_PRIVATE)
 /**
  * \brief           Configure asynchronous private key operation callbacks.
diff --git a/tests/suites/test_suite_ssl.function b/tests/suites/test_suite_ssl.function
index dd8c262..38a2602 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;
 }
@@ -2194,6 +2212,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 );