mirror of
https://gitlab.com/chrony/chrony.git
synced 2025-12-04 15:25:06 -05:00
util: add function for constant-time memory comparison
Add a function to check if two buffers of the same length contain the same data, but do the comparison in a constant time with respect to the returned value to avoid creating a timing side channel, i.e. the time depends only on the buffer length, not on the content. Use the gnutls_memcmp() or nettle_memeql_sec() functions if available, otherwise use the same algorithm as nettle - bitwise ORing XORed data.
This commit is contained in:
2
configure
vendored
2
configure
vendored
@@ -888,6 +888,7 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_nettle = "1" ];
|
|||||||
HASH_OBJ="hash_nettle.o"
|
HASH_OBJ="hash_nettle.o"
|
||||||
HASH_LINK="$test_link"
|
HASH_LINK="$test_link"
|
||||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||||
|
add_def HAVE_NETTLE
|
||||||
add_def FEAT_SECHASH
|
add_def FEAT_SECHASH
|
||||||
|
|
||||||
if test_code 'CMAC in nettle' 'nettle/cmac.h' "$test_cflags" "$test_link" \
|
if test_code 'CMAC in nettle' 'nettle/cmac.h' "$test_cflags" "$test_link" \
|
||||||
@@ -910,6 +911,7 @@ if [ $feat_sechash = "1" ] && [ "x$HASH_LINK" = "x" ] && [ $try_gnutls = "1" ];
|
|||||||
HASH_OBJ="hash_gnutls.o"
|
HASH_OBJ="hash_gnutls.o"
|
||||||
HASH_LINK="$test_link"
|
HASH_LINK="$test_link"
|
||||||
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
MYCPPFLAGS="$MYCPPFLAGS $test_cflags"
|
||||||
|
add_def HAVE_GNUTLS
|
||||||
add_def FEAT_SECHASH
|
add_def FEAT_SECHASH
|
||||||
|
|
||||||
if test_code 'CMAC in gnutls' 'gnutls/crypto.h' "$test_cflags" "$test_link" \
|
if test_code 'CMAC in gnutls' 'gnutls/crypto.h' "$test_cflags" "$test_link" \
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ handle_signal(int signal)
|
|||||||
void
|
void
|
||||||
test_unit(void)
|
test_unit(void)
|
||||||
{
|
{
|
||||||
|
char buf[16], buf2[16], *s, *s2, *words[3];
|
||||||
struct timespec ts, ts2, ts3, ts4;
|
struct timespec ts, ts2, ts3, ts4;
|
||||||
char buf[16], *s, *s2, *words[3];
|
|
||||||
NTP_int64 ntp_ts, ntp_ts2, ntp_fuzz;
|
NTP_int64 ntp_ts, ntp_ts2, ntp_fuzz;
|
||||||
NTP_int32 ntp32_ts;
|
NTP_int32 ntp32_ts;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
@@ -797,5 +797,19 @@ test_unit(void)
|
|||||||
TEST_CHECK(strcmp(words[0], "a") == 0);
|
TEST_CHECK(strcmp(words[0], "a") == 0);
|
||||||
TEST_CHECK(strcmp(words[1], "b") == 0);
|
TEST_CHECK(strcmp(words[1], "b") == 0);
|
||||||
|
|
||||||
|
for (i = 0; i < 1000; i++) {
|
||||||
|
UTI_GetRandomBytes(buf, sizeof (buf));
|
||||||
|
memcpy(buf2, buf, sizeof (buf));
|
||||||
|
for (j = 0; j < sizeof (buf); j++)
|
||||||
|
TEST_CHECK(UTI_IsMemoryEqual(buf, buf2, j));
|
||||||
|
|
||||||
|
for (j = 0; j < 8 * sizeof (buf); j++) {
|
||||||
|
buf2[j / 8] ^= 1U << j % 8;
|
||||||
|
TEST_CHECK(!UTI_IsMemoryEqual(buf, buf2, sizeof (buf)));
|
||||||
|
buf2[j / 8] ^= 1U << j % 8;
|
||||||
|
TEST_CHECK(UTI_IsMemoryEqual(buf, buf2, sizeof (buf)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HSH_Finalise();
|
HSH_Finalise();
|
||||||
}
|
}
|
||||||
|
|||||||
25
util.c
25
util.c
@@ -29,6 +29,12 @@
|
|||||||
|
|
||||||
#include "sysincl.h"
|
#include "sysincl.h"
|
||||||
|
|
||||||
|
#if defined(HAVE_NETTLE)
|
||||||
|
#include <nettle/memops.h>
|
||||||
|
#elif defined(HAVE_GNUTLS)
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@@ -1648,3 +1654,22 @@ UTI_SplitString(char *string, char **words, int max_saved_words)
|
|||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ================================================== */
|
||||||
|
|
||||||
|
int
|
||||||
|
UTI_IsMemoryEqual(const void *s1, const void *s2, unsigned int len)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_NETTLE)
|
||||||
|
return nettle_memeql_sec(s1, s2, len);
|
||||||
|
#elif defined(HAVE_GNUTLS)
|
||||||
|
return gnutls_memcmp(s1, s2, len) == 0;
|
||||||
|
#else
|
||||||
|
unsigned int i, x;
|
||||||
|
|
||||||
|
for (i = 0, x = 0; i < len; i++)
|
||||||
|
x |= ((const unsigned char *)s1)[i] ^ ((const unsigned char *)s2)[i];
|
||||||
|
|
||||||
|
return x == 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|||||||
5
util.h
5
util.h
@@ -257,6 +257,11 @@ extern unsigned int UTI_HexToBytes(const char *hex, void *buf, unsigned int len)
|
|||||||
number of pointers to the words. */
|
number of pointers to the words. */
|
||||||
extern int UTI_SplitString(char *string, char **words, int max_saved_words);
|
extern int UTI_SplitString(char *string, char **words, int max_saved_words);
|
||||||
|
|
||||||
|
/* Check if two buffers of the same length contain the same data, but do the
|
||||||
|
comparison in constant time with respect to the returned value to avoid
|
||||||
|
creating a timing side channel */
|
||||||
|
extern int UTI_IsMemoryEqual(const void *s1, const void *s2, unsigned int len);
|
||||||
|
|
||||||
/* Macros to get maximum and minimum of two values */
|
/* Macros to get maximum and minimum of two values */
|
||||||
#ifdef MAX
|
#ifdef MAX
|
||||||
#undef MAX
|
#undef MAX
|
||||||
|
|||||||
Reference in New Issue
Block a user