Mercurial > dovecot > core-2.2
changeset 21951:3ef988b95d96
lib: Add mem_equals_timing_safe()
author | Timo Sirainen <timo.sirainen@dovecot.fi> |
---|---|
date | Sun, 09 Apr 2017 00:49:37 +0300 |
parents | 86b0d2fb44d3 |
children | e19e015f7449 |
files | src/lib/strfuncs.c src/lib/strfuncs.h src/lib/test-strfuncs.c |
diffstat | 3 files changed, 45 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/strfuncs.c Mon Apr 10 20:53:29 2017 +0300 +++ b/src/lib/strfuncs.c Sun Apr 09 00:49:37 2017 +0300 @@ -15,6 +15,8 @@ const unsigned char uchar_nul = '\0'; +volatile int timing_safety_unoptimization; + int i_snprintf(char *dest, size_t max_chars, const char *format, ...) { va_list args; @@ -474,6 +476,21 @@ return strcasecmp(*p1, *p2); } +bool mem_equals_timing_safe(const void *p1, const void *p2, size_t size) +{ + const unsigned char *s1 = p1, *s2 = p2; + size_t i; + int ret = 0; + + for (i = 0; i < size; i++) + ret |= s1[i] ^ s2[i]; + + /* make sure the compiler optimizer doesn't try to break out of the + above loop early. */ + timing_safety_unoptimization = ret; + return ret == 0; +} + static char ** split_str(pool_t pool, const char *data, const char *separators, int spaces) {
--- a/src/lib/strfuncs.h Mon Apr 10 20:53:29 2017 +0300 +++ b/src/lib/strfuncs.h Sun Apr 09 00:49:37 2017 +0300 @@ -66,6 +66,9 @@ int i_memcasecmp(const void *p1, const void *p2, size_t size) ATTR_PURE; int i_strcmp_p(const char *const *p1, const char *const *p2) ATTR_PURE; int i_strcasecmp_p(const char *const *p1, const char *const *p2) ATTR_PURE; +/* Returns TRUE if the two memory areas are equal. This function is safe + against timing attacks, so it compares all the bytes every time. */ +bool mem_equals_timing_safe(const void *p1, const void *p2, size_t size); static inline char *i_strchr_to_next(const char *str, char chr) {
--- a/src/lib/test-strfuncs.c Mon Apr 10 20:53:29 2017 +0300 +++ b/src/lib/test-strfuncs.c Sun Apr 09 00:49:37 2017 +0300 @@ -236,6 +236,30 @@ test_end(); } +static void test_mem_equals_timing_safe(void) +{ + const struct { + const char *a, *b; + } tests[] = { + { "", "" }, + { "a", "a" }, + { "b", "a" }, + { "ab", "ab" }, + { "ab", "ba" }, + { "ab", "bc" }, + }; + test_begin("mem_equals_timing_safe()"); + for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) { + size_t len = strlen(tests[i].a); + i_assert(len == strlen(tests[i].b)); + test_assert((memcmp(tests[i].a, tests[i].b, len) == 0) == + mem_equals_timing_safe(tests[i].a, tests[i].b, len)); + test_assert((memcmp(tests[i].a, tests[i].b, len) == 0) == + mem_equals_timing_safe(tests[i].b, tests[i].a, len)); + } + test_end(); +} + void test_strfuncs(void) { test_p_strarray_dup(); @@ -248,4 +272,5 @@ test_t_str_rtrim(); test_t_strarray_join(); test_p_array_const_string_join(); + test_mem_equals_timing_safe(); }