Add macro for error code addition

Adds a macro (`MBEDTLS_ERR_ADD`) to add error codes together and check that the
result will not be corrupted. This additional check is only enabled during
testing when `MBEDTLS_TEST_HOOKS` is defined.

Also includes a reference usage example in `rsa.c` where two high-level error
codes could be incorrectly added together under the right conditions. This now
ensures that when this error occurs during testing it will be correctly
reported.

Signed-off-by: Chris Jones <christopher.jones@arm.com>
diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h
index cd7731e..d164e9f 100644
--- a/include/mbedtls/error.h
+++ b/include/mbedtls/error.h
@@ -114,6 +114,16 @@
 #define MBEDTLS_ERR_ERROR_GENERIC_ERROR       -0x0001  /**< Generic error */
 #define MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED -0x006E  /**< This is a bug in the library */
 
+#if defined(MBEDTLS_TEST_HOOKS)
+void (*mbedtls_test_err_add_hook)( int, int, const char *, int );
+int mbedtls_err_add( int high, int low, const char *file, int line );
+#define MBEDTLS_ERR_ADD( high, low )  \
+    ( mbedtls_err_add( high, low, __FILE__, __LINE__ ) )
+#else
+#define MBEDTLS_ERR_ADD( high, low ) \
+    ( high + low )
+#endif
+
 /**
  * \brief Translate a mbed TLS error code into a string representation,
  *        Result is truncated if necessary and always includes a terminating
diff --git a/library/error.c b/library/error.c
index 901a369..486afed 100644
--- a/library/error.c
+++ b/library/error.c
@@ -210,6 +210,13 @@
 #include "mbedtls/xtea.h"
 #endif
 
+#if defined(MBEDTLS_TEST_HOOKS)
+int mbedtls_err_add( int high, int low, const char *file, int line ) {
+    if( mbedtls_test_err_add_hook != NULL )
+        (*mbedtls_test_err_add_hook)( high, low, file, line );
+    return ( high + low );
+}
+#endif
 
 const char * mbedtls_high_level_strerr( int error_code )
 {
diff --git a/library/rsa.c b/library/rsa.c
index fea76bf..f4bec46 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -1085,7 +1085,7 @@
     mbedtls_mpi_free( &I );
 
     if( ret != 0 && ret >= -0x007f )
-        return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret );
+        return( MBEDTLS_ERR_ADD( MBEDTLS_ERR_RSA_PRIVATE_FAILED, ret ) );
 
     return( ret );
 }
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index c3a844b..1fe25d8 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -278,4 +278,14 @@
 void mbedtls_test_mutex_usage_check( void );
 #endif /* MBEDTLS_TEST_MUTEX_USAGE */
 
+#if defined(MBEDTLS_TEST_HOOKS)
+/**
+ * \brief	Check that a pure high-level error code is being combined with a
+ *			pure low-level error code as otherwise the resultant error code
+ *			would be corrupted.
+ */
+void mbedtls_test_err_add_check( int high, int low,
+                                 const char *file, int line);
+#endif
+
 #endif /* TEST_HELPERS_H */
diff --git a/tests/src/helpers.c b/tests/src/helpers.c
index e323275..2c01a58 100644
--- a/tests/src/helpers.c
+++ b/tests/src/helpers.c
@@ -282,3 +282,16 @@
     }
 }
 #endif /* MBEDTLS_CHECK_PARAMS */
+
+#if defined(MBEDTLS_TEST_HOOKS)
+void mbedtls_test_err_add_check( int high, int low,
+                                 const char *file, int line )
+{
+    if ( high < -0x0FFF && low > -0x007F )
+    {
+        mbedtls_fprintf( stderr, "\nIncorrect error code addition at %s:%d\n",
+                                file, line );
+        mbedtls_exit( 1 );
+    }
+}
+#endif /* MBEDTLS_TEST_HOOKS */
diff --git a/tests/suites/main_test.function b/tests/suites/main_test.function
index 36a7d23..6a4758a 100644
--- a/tests/suites/main_test.function
+++ b/tests/suites/main_test.function
@@ -33,6 +33,10 @@
 #include "psa/crypto.h"
 #endif /* MBEDTLS_USE_PSA_CRYPTO */
 
+#if defined(MBEDTLS_TEST_HOOKS)
+#include "mbedtls/error.h"
+#endif
+
 /* Test code may use deprecated identifiers only if the preprocessor symbol
  * MBEDTLS_TEST_DEPRECATED is defined. When building tests, set
  * MBEDTLS_TEST_DEPRECATED explicitly if MBEDTLS_DEPRECATED_WARNING is
@@ -279,6 +283,10 @@
  */
 int main( int argc, const char *argv[] )
 {
+#if defined(MBEDTLS_TEST_HOOKS)
+    mbedtls_test_err_add_hook = &mbedtls_test_err_add_check;
+#endif
+
     int ret = mbedtls_test_platform_setup();
     if( ret != 0 )
     {