diff --git a/src/contrib/string.c b/src/contrib/string.c index 51cfd79ea8956e884d6c69ea8ace4b32edfcbefa..40439d465cb6fd74e43f89b66dffb669f8a5e0a5 100644 --- a/src/contrib/string.c +++ b/src/contrib/string.c @@ -91,3 +91,14 @@ char *strstrip(const char *str) return trimmed; } + +int const_time_memcmp(const void *s1, const void *s2, size_t n) +{ + volatile uint8_t equal = 0; + + for (size_t i = 0; i < n; i++) { + equal |= ((uint8_t *)s1)[i] ^ ((uint8_t *)s2)[i]; + } + + return equal; +} diff --git a/src/contrib/string.h b/src/contrib/string.h index 36fca73e84c293daa47dcf2338ab32651e9b9215..5934de81b07c0cab405c5d4f21aa1ebcad13401f 100644 --- a/src/contrib/string.h +++ b/src/contrib/string.h @@ -61,4 +61,16 @@ char *strcdup(const char *s1, const char *s2); */ char *strstrip(const char *str); +/*! + * \brief Compare data in time based on string length. + * This function just checks for (in)equality not for relation + * + * \param s1 The first address to compare. + * \param s2 The second address to compare. + * \param n The size of memory to compare. + * + * \return Non zero on difference and zero if the buffers are identical. + */ +int const_time_memcmp(const void *s1, const void *s2, size_t n); + /*! @} */ diff --git a/src/libknot/tsig-op.c b/src/libknot/tsig-op.c index 60fe6f8044520344c2bab8f5860f7d0a94a64ba4..c2776a503e8e13590dcfdb80c79d8e1fa3f3652a 100644 --- a/src/libknot/tsig-op.c +++ b/src/libknot/tsig-op.c @@ -29,6 +29,7 @@ #include "libknot/packet/wire.h" #include "libknot/consts.h" #include "libknot/packet/rrset-wire.h" +#include "contrib/string.h" #include "contrib/wire.h" const int KNOT_TSIG_MAX_DIGEST_SIZE = 64; // size of HMAC-SHA512 digest @@ -581,7 +582,7 @@ static int check_digest(const knot_rrset_t *tsig_rr, return KNOT_TSIG_EBADSIG; } - if (memcmp(tsig_mac, digest_tmp, mac_length) != 0) { + if (const_time_memcmp(tsig_mac, digest_tmp, mac_length) != 0) { return KNOT_TSIG_EBADSIG; }