From c05f1506f41ef548680f4898245f693632a78152 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 6 Nov 2019 10:15:26 +0100 Subject: [PATCH 1/8] Introduce return values for tinycrypt functions Currently functions that may return success or failure tend to do so by returning 0 or 1. If an active physical attacker can flip a bit in memory or registers at the right time, they may easily change a failure value into a success value, with potentially catastrophic security consequences. As typical attackers can only flip a few bits, an element of protection against such attacks is to ensure a sufficient Hamming distance between failure values and the success value. This commit introduces such values, which will put to use in critical functions in future commits. In addition to SUCCESS and FAILURE, a third value ATTACK_DETECTED is introduced, which can be used later when suspicious-looking events are noticed (static data changed when it shouldn't, double condition checking returning inconsistent results, etc.). Values are chosen so that Hamming distances are large, and that no value is the complement of another, in order to avoid unwanted compiler optimisations. Note: the error values used by Mbed TLS are already safe (assuming 32-bit integers) as they are of the form -x with x in the range [1, 2^15) so their Hamming distance with the success value (0) is at least 17, so it's hard for an attacker to turn an error value into the success value (or vice-versa). --- include/tinycrypt/ecc.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/tinycrypt/ecc.h b/include/tinycrypt/ecc.h index 2da74b3c0..9a705c495 100644 --- a/include/tinycrypt/ecc.h +++ b/include/tinycrypt/ecc.h @@ -83,6 +83,13 @@ extern "C" { #endif +/* Return values for functions, chosen with large Hamming distances between + * them (especially to SUCESS) to mitigate the impact of fault injection + * attacks flipping a low number of bits. */ +#define UECC_SUCCESS 0 +#define UECC_FAILURE 0x75555555 +#define UECC_ATTACK_DETECTED 0x7aaaaaaa + /* Word size (4 bytes considering 32-bits architectures) */ #define uECC_WORD_SIZE 4 From 10d8e8ed64158e12fe4279ea59d5b383433ab24f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 6 Nov 2019 10:30:26 +0100 Subject: [PATCH 2/8] Use safer return values in uECC_verify() This is a first step in protecting against fault injection attacks: the attacker can no longer change failure into success by flipping a single bit. Additional steps are needed to prevent other attacks (instruction skip etc) and will be the object of future commits. The return value of uECC_vli_equal() should be protected as well, which will be done in a future commit as well. --- include/tinycrypt/ecc_dsa.h | 4 ++-- library/pk.c | 2 +- tests/suites/test_suite_tinycrypt.data | 2 +- tests/suites/test_suite_tinycrypt.function | 9 ++++----- tinycrypt/ecc_dsa.c | 9 ++++++--- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/include/tinycrypt/ecc_dsa.h b/include/tinycrypt/ecc_dsa.h index e54a77e85..55b9d43f3 100644 --- a/include/tinycrypt/ecc_dsa.h +++ b/include/tinycrypt/ecc_dsa.h @@ -123,8 +123,8 @@ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, /** * @brief Verify an ECDSA signature. - * @return returns TC_SUCCESS (1) if the signature is valid - * returns TC_FAIL (0) if the signature is invalid. + * @return returns UECC_SUCCESS if the signature is valid + * returns UECC_FAILURE if the signature is invalid. * * @param p_public_key IN -- The signer's public key. * @param p_message_hash IN -- The hash of the signed data. diff --git a/library/pk.c b/library/pk.c index 29123eb05..857bafc2d 100644 --- a/library/pk.c +++ b/library/pk.c @@ -591,7 +591,7 @@ static int uecc_eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, ret = uECC_verify( keypair->public_key, hash, (unsigned) hash_len, signature, uecc_curve ); - if( ret == 0 ) + if( ret != UECC_SUCCESS ) return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); return( 0 ); diff --git a/tests/suites/test_suite_tinycrypt.data b/tests/suites/test_suite_tinycrypt.data index ac2a8e23e..2c4d54b5a 100644 --- a/tests/suites/test_suite_tinycrypt.data +++ b/tests/suites/test_suite_tinycrypt.data @@ -8,4 +8,4 @@ ECDH primitive rfc 5903 p256 ecdh_primitive_testvec:"C88F01F510D9AC3F70A292DAA2316DE544E9AAB8AFE84049C62A9C57862D1433":"DAD0B65394221CF9B051E1FECA5787D098DFE637FC90B9EF945D0C3772581180":"5271A0461CDB8252D61F1C456FA3E59AB1F45B33ACCF5F58389E0577B8990BB3":"C6EF9C5D78AE012A011164ACB397CE2088685D8F06BF9BE0B283AB46476BEE53":"D12DFB5289C8D4F81208B70270398C342296970A0BCCB74C736FC7554494BF63":"56FBF3CA366CC23E8157854C13C58D6AAC23F046ADA30F8353E74F33039872AB":"D6840F6B42F6EDAFD13116E0E12565202FEF8E9ECE7DCE03812464D04B9442DE" ECDSA primitive rfc 4754 p256 -ecdsa_primitive_testvec:"2442A5CC0ECD015FA3CA31DC8E2BBC70BF42D60CBCA20085E0822CB04235E970":"6FC98BD7E50211A4A27102FA3549DF79EBCB4BF246B80945CDDFE7D509BBFD7D":"BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD":"CB28E0999B9C7715FD0A80D8E47A77079716CBBF917DD72E97566EA1C066957C":"86FA3BB4E26CAD5BF90B7F81899256CE7594BB1EA0C89212748BFF3B3D5B0315":1 +ecdsa_primitive_testvec:"2442A5CC0ECD015FA3CA31DC8E2BBC70BF42D60CBCA20085E0822CB04235E970":"6FC98BD7E50211A4A27102FA3549DF79EBCB4BF246B80945CDDFE7D509BBFD7D":"BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD":"CB28E0999B9C7715FD0A80D8E47A77079716CBBF917DD72E97566EA1C066957C":"86FA3BB4E26CAD5BF90B7F81899256CE7594BB1EA0C89212748BFF3B3D5B0315" diff --git a/tests/suites/test_suite_tinycrypt.function b/tests/suites/test_suite_tinycrypt.function index 24b331d80..664cd0862 100644 --- a/tests/suites/test_suite_tinycrypt.function +++ b/tests/suites/test_suite_tinycrypt.function @@ -55,7 +55,7 @@ void test_ecdsa() TEST_ASSERT( uECC_sign( private, hash, sizeof( hash ), sig, curve ) != 0 ); - TEST_ASSERT( uECC_verify( public, hash, sizeof( hash ), sig, curve ) != 0 ); + TEST_ASSERT( uECC_verify( public, hash, sizeof( hash ), sig, curve ) == UECC_SUCCESS ); } /* END_CASE */ @@ -88,8 +88,7 @@ void ecdh_primitive_testvec( data_t * private1, data_t * xA_str, /* BEGIN_CASE depends_on:MBEDTLS_USE_TINYCRYPT */ void ecdsa_primitive_testvec( data_t * xQ_str, data_t * yQ_str, - data_t * hash, data_t * r_str, data_t * s_str, - int result ) + data_t * hash, data_t * r_str, data_t * s_str ) { const struct uECC_Curve_t * curve = uECC_secp256r1(); uint8_t pub_bytes[2*NUM_ECC_BYTES] = {0}; @@ -101,7 +100,7 @@ void ecdsa_primitive_testvec( data_t * xQ_str, data_t * yQ_str, memcpy( sig_bytes + NUM_ECC_BYTES, s_str->x, r_str->len ); TEST_ASSERT( uECC_verify( pub_bytes, hash->x, hash->len, - sig_bytes, curve ) == result ); + sig_bytes, curve ) == UECC_SUCCESS ); // Alter the signature and check the verification fails for( int i = 0; i < 2*NUM_ECC_BYTES; i++ ) @@ -109,7 +108,7 @@ void ecdsa_primitive_testvec( data_t * xQ_str, data_t * yQ_str, uint8_t temp = sig_bytes[i]; sig_bytes[i] = ( sig_bytes[i] + 1 ) % 256; TEST_ASSERT( uECC_verify( pub_bytes, hash->x, hash->len, - sig_bytes, curve ) == 0 ); + sig_bytes, curve ) == UECC_FAILURE ); sig_bytes[i] = temp; } diff --git a/tinycrypt/ecc_dsa.c b/tinycrypt/ecc_dsa.c index 04b1bfabd..5cf58f31f 100644 --- a/tinycrypt/ecc_dsa.c +++ b/tinycrypt/ecc_dsa.c @@ -235,13 +235,13 @@ int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, /* r, s must not be 0. */ if (uECC_vli_isZero(r) || uECC_vli_isZero(s)) { - return 0; + return UECC_FAILURE; } /* r, s must be < n. */ if (uECC_vli_cmp_unsafe(curve->n, r) != 1 || uECC_vli_cmp_unsafe(curve->n, s) != 1) { - return 0; + return UECC_FAILURE; } /* Calculate u1 and u2. */ @@ -301,7 +301,10 @@ int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, } /* Accept only if v == r. */ - return (int)(uECC_vli_equal(rx, r) == 0); + if (uECC_vli_equal(rx, r) == 0) + return UECC_SUCCESS; + + return UECC_FAILURE; } #else typedef int mbedtls_dummy_tinycrypt_def; From 2b6312b7d90cbcb97f3f53d92d124422af3cb60b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 6 Nov 2019 10:42:02 +0100 Subject: [PATCH 3/8] Harden return value of uECC_vli_equal() Previously it was returning 0 or 1, so flipping a single bit in the return value reversed its meaning. Now it's returning the diff itself. This is safe because in the two places it's used (signature verification and point validation), invalid values will have a large number of bits differing from the expected value, so diff will have a large Hamming weight. An alternative would be to return for example -!(diff == 0), but the comparison itself is prone to attacks (glitching the appropriate flag in the CPU flags register, or the conditional branch if the comparison uses one). So we'd need to protect the comparison, and it's simpler to just skip it and return diff itself. --- include/tinycrypt/ecc.h | 2 +- tinycrypt/ecc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/tinycrypt/ecc.h b/include/tinycrypt/ecc.h index 9a705c495..0d1d9ec98 100644 --- a/include/tinycrypt/ecc.h +++ b/include/tinycrypt/ecc.h @@ -422,7 +422,7 @@ uECC_word_t uECC_vli_sub(uECC_word_t *result, const uECC_word_t *left, * @param left IN -- left term in comparison * @param right IN -- right term in comparison * @param num_words IN -- number of words - * @return Returns 0 if left == right, 1 otherwise. + * @return Returns 0 if left == right, non-zero otherwise. */ uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right); diff --git a/tinycrypt/ecc.c b/tinycrypt/ecc.c index d01c67617..92906fd76 100644 --- a/tinycrypt/ecc.c +++ b/tinycrypt/ecc.c @@ -185,7 +185,7 @@ uECC_word_t uECC_vli_equal(const uECC_word_t *left, const uECC_word_t *right) for (i = NUM_ECC_WORDS - 1; i >= 0; --i) { diff |= (left[i] ^ right[i]); } - return !(diff == 0); + return diff; } uECC_word_t cond_set(uECC_word_t p_true, uECC_word_t p_false, unsigned int cond) From e6d6f17738b46a73bbf255073a96899b1667840d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 6 Nov 2019 11:14:38 +0100 Subject: [PATCH 4/8] Add double-checking of critical value in uECC_verify() This hardens against attacks that glitch the conditional branch by making it necessary for the attacker to inject two consecutive faults instead of one. If desired, we could insert a random delay in order to further protect against double-glitch attacks. Also, when a single glitch is detected we report it. --- tinycrypt/ecc_dsa.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tinycrypt/ecc_dsa.c b/tinycrypt/ecc_dsa.c index 5cf58f31f..687ea9880 100644 --- a/tinycrypt/ecc_dsa.c +++ b/tinycrypt/ecc_dsa.c @@ -214,6 +214,7 @@ int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, const uECC_word_t *point; bitcount_t num_bits; bitcount_t i; + volatile uECC_word_t diff; uECC_word_t _public[NUM_ECC_WORDS * 2]; uECC_word_t r[NUM_ECC_WORDS], s[NUM_ECC_WORDS]; @@ -301,8 +302,15 @@ int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, } /* Accept only if v == r. */ - if (uECC_vli_equal(rx, r) == 0) - return UECC_SUCCESS; + diff = uECC_vli_equal(rx, r); + if (diff == 0) { + if (diff == 0) { + return UECC_SUCCESS; + } + else { + return UECC_ATTACK_DETECTED; + } + } return UECC_FAILURE; } From 324c6e9cc9768f435f0f13bf66b3df449b94ceb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 6 Nov 2019 11:52:41 +0100 Subject: [PATCH 5/8] Add error code MBEDTLS_ERR_PLATFORM_FAULT_DETECTED This can be used by Mbed TLS functions in any module to signal that a fault attack is likely happening, so this can be appropriately handled by the application (report, fall back to safer mode or even halt, etc.) --- include/mbedtls/error.h | 2 +- include/mbedtls/platform.h | 1 + library/error.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/mbedtls/error.h b/include/mbedtls/error.h index 31f294f70..a52f9f5db 100644 --- a/include/mbedtls/error.h +++ b/include/mbedtls/error.h @@ -86,7 +86,7 @@ * CHACHA20 3 0x0051-0x0055 * POLY1305 3 0x0057-0x005B * CHACHAPOLY 2 0x0054-0x0056 - * PLATFORM 1 0x0070-0x0072 + * PLATFORM 3 0x0070-0x0072 0x0071-0x0071 * * High-level module nr (3 bits - 0x0...-0x7...) * Name ID Nr of Errors diff --git a/include/mbedtls/platform.h b/include/mbedtls/platform.h index 89fe8a7b1..82d5e3355 100644 --- a/include/mbedtls/platform.h +++ b/include/mbedtls/platform.h @@ -45,6 +45,7 @@ #define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED -0x0070 /**< Hardware accelerator failed */ #define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */ +#define MBEDTLS_ERR_PLATFORM_FAULT_DETECTED -0x0071 /**< A fault was detected in a critical path, likely indicative of an active physical attack */ #ifdef __cplusplus extern "C" { diff --git a/library/error.c b/library/error.c index c993524fe..77c713374 100644 --- a/library/error.c +++ b/library/error.c @@ -841,6 +841,8 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) mbedtls_snprintf( buf, buflen, "PLATFORM - Hardware accelerator failed" ); if( use_ret == -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) ) mbedtls_snprintf( buf, buflen, "PLATFORM - The requested feature is not supported by the platform" ); + if( use_ret == -(MBEDTLS_ERR_PLATFORM_FAULT_DETECTED) ) + mbedtls_snprintf( buf, buflen, "PLATFORM - A fault was detected in a critical path, likely indicative of an active physical attack" ); #endif /* MBEDTLS_PLATFORM_C */ #if defined(MBEDTLS_POLY1305_C) From ca7b5ab5ef0e8943fda34c6347a2f10136bd7fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 6 Nov 2019 11:56:25 +0100 Subject: [PATCH 6/8] Use double-checking of critical value in pk_verify() Also change the flow so that the default return value is a failing one. --- library/pk.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/library/pk.c b/library/pk.c index 857bafc2d..eaaa371b7 100644 --- a/library/pk.c +++ b/library/pk.c @@ -577,6 +577,7 @@ static int uecc_eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, const unsigned char *sig, size_t sig_len ) { int ret; + volatile int ret_fi; uint8_t signature[2*NUM_ECC_BYTES]; unsigned char *p; const struct uECC_Curve_t * uecc_curve = uECC_secp256r1(); @@ -589,12 +590,21 @@ static int uecc_eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, if( ret != 0 ) return( ret ); - ret = uECC_verify( keypair->public_key, hash, - (unsigned) hash_len, signature, uecc_curve ); - if( ret != UECC_SUCCESS ) - return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); + ret_fi = uECC_verify( keypair->public_key, hash, + (unsigned) hash_len, signature, uecc_curve ); - return( 0 ); + if( ret_fi == UECC_ATTACK_DETECTED ) + return( MBEDTLS_ERR_PLATFORM_FAULT_DETECTED ); + + if( ret_fi == UECC_SUCCESS ) + { + if( ret_fi == UECC_SUCCESS ) + return( 0 ); + else + return( MBEDTLS_ERR_PLATFORM_FAULT_DETECTED ); + } + + return( MBEDTLS_ERR_PK_HW_ACCEL_FAILED ); } /* From 72a8c9e7dcca83a17c2c8429311822ab6bdbc450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 8 Nov 2019 10:21:00 +0100 Subject: [PATCH 7/8] Force some compilers to respect volatile reads Inspection of the generated assembly showed that before this commit, armcc 5 was optimizing away the successive reads to the volatile local variable that's used for double-checks. Inspection also reveals that inserting a call to an external function is enough to prevent it from doing that. The tested versions of ARM-GCC, Clang and Armcc 6 (aka armclang) all keep the double read, with our without a call to an external function in the middle. The inserted function can also be changed to insert a random delay if desired in the future, as it is appropriately places between the reads. --- include/mbedtls/platform_util.h | 7 +++++++ library/pk.c | 1 + library/platform_util.c | 9 +++++++++ tinycrypt/ecc_dsa.c | 2 ++ 4 files changed, 19 insertions(+) diff --git a/include/mbedtls/platform_util.h b/include/mbedtls/platform_util.h index 586f0d9ee..e20f1c32e 100644 --- a/include/mbedtls/platform_util.h +++ b/include/mbedtls/platform_util.h @@ -238,6 +238,13 @@ int mbedtls_platform_memcmp( const void *buf1, const void *buf2, size_t num ); */ uint32_t mbedtls_platform_random_in_range( size_t num ); +/** + * \brief This function does nothing, but can be inserted between + * successive reads to a volatile local variable to prevent + * compilers from optimizing them away. + */ +void mbedtls_platform_enforce_volatile_reads( void ); + #if defined(MBEDTLS_HAVE_TIME_DATE) /** * \brief Platform-specific implementation of gmtime_r() diff --git a/library/pk.c b/library/pk.c index eaaa371b7..9eddb61ab 100644 --- a/library/pk.c +++ b/library/pk.c @@ -598,6 +598,7 @@ static int uecc_eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, if( ret_fi == UECC_SUCCESS ) { + mbedtls_platform_enforce_volatile_reads(); if( ret_fi == UECC_SUCCESS ) return( 0 ); else diff --git a/library/platform_util.c b/library/platform_util.c index 1a0fefae6..97dfe73ef 100644 --- a/library/platform_util.c +++ b/library/platform_util.c @@ -168,6 +168,15 @@ uint32_t mbedtls_platform_random_in_range( size_t num ) #endif } +/* Some compilers (armcc 5 for example) optimize away successive reads from a + * volatile local variable (which we use as a counter-measure to fault + * injection attacks), unless there is a call to an external function between + * them. This functions doesn't need to do anything, it just needs to be + * in another compilation unit. So here's a function that does nothing. */ +void mbedtls_platform_enforce_volatile_reads( void ) +{ +} + #if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_PLATFORM_GMTIME_R_ALT) #include #if !defined(_WIN32) && (defined(unix) || \ diff --git a/tinycrypt/ecc_dsa.c b/tinycrypt/ecc_dsa.c index 687ea9880..6c171c3a9 100644 --- a/tinycrypt/ecc_dsa.c +++ b/tinycrypt/ecc_dsa.c @@ -67,6 +67,7 @@ #if defined(MBEDTLS_USE_TINYCRYPT) #include #include +#include "mbedtls/platform_util.h" #if default_RNG_defined static uECC_RNG_Function g_rng_function = &default_CSPRNG; @@ -304,6 +305,7 @@ int uECC_verify(const uint8_t *public_key, const uint8_t *message_hash, /* Accept only if v == r. */ diff = uECC_vli_equal(rx, r); if (diff == 0) { + mbedtls_platform_enforce_volatile_reads(); if (diff == 0) { return UECC_SUCCESS; } From 766c9e9781e09a967d8e0b36a65f026886dbf4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 29 Nov 2019 09:39:14 +0100 Subject: [PATCH 8/8] Improve description of ERR_PLATFORM_FAULT_DETECTED --- include/mbedtls/platform.h | 2 +- library/error.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mbedtls/platform.h b/include/mbedtls/platform.h index 82d5e3355..16f9b8a3c 100644 --- a/include/mbedtls/platform.h +++ b/include/mbedtls/platform.h @@ -45,7 +45,7 @@ #define MBEDTLS_ERR_PLATFORM_HW_ACCEL_FAILED -0x0070 /**< Hardware accelerator failed */ #define MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED -0x0072 /**< The requested feature is not supported by the platform */ -#define MBEDTLS_ERR_PLATFORM_FAULT_DETECTED -0x0071 /**< A fault was detected in a critical path, likely indicative of an active physical attack */ +#define MBEDTLS_ERR_PLATFORM_FAULT_DETECTED -0x0071 /**< A hardware fault was detected in a critical path. As a security precaution this should be treated as a potential physical attack */ #ifdef __cplusplus extern "C" { diff --git a/library/error.c b/library/error.c index 77c713374..74c9d0b39 100644 --- a/library/error.c +++ b/library/error.c @@ -842,7 +842,7 @@ void mbedtls_strerror( int ret, char *buf, size_t buflen ) if( use_ret == -(MBEDTLS_ERR_PLATFORM_FEATURE_UNSUPPORTED) ) mbedtls_snprintf( buf, buflen, "PLATFORM - The requested feature is not supported by the platform" ); if( use_ret == -(MBEDTLS_ERR_PLATFORM_FAULT_DETECTED) ) - mbedtls_snprintf( buf, buflen, "PLATFORM - A fault was detected in a critical path, likely indicative of an active physical attack" ); + mbedtls_snprintf( buf, buflen, "PLATFORM - A hardware fault was detected in a critical path. As a security precaution this should be treated as a potential physical attack" ); #endif /* MBEDTLS_PLATFORM_C */ #if defined(MBEDTLS_POLY1305_C)