From: Timo Sirainen Date: Tue, 7 Apr 2020 16:16:10 +0000 (+0300) Subject: lib: Add str_equals_timing_almost_safe() X-Git-Tag: 2.3.11.2~352 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5a73613c7ca029fa7555e84fd1d9f802c2da956a;p=thirdparty%2Fdovecot%2Fcore.git lib: Add str_equals_timing_almost_safe() --- diff --git a/src/lib/strfuncs.c b/src/lib/strfuncs.c index cf98e12753..49fe81872f 100644 --- a/src/lib/strfuncs.c +++ b/src/lib/strfuncs.c @@ -583,6 +583,21 @@ bool mem_equals_timing_safe(const void *p1, const void *p2, size_t size) return ret == 0; } +bool str_equals_timing_almost_safe(const char *s1, const char *s2) +{ + size_t i; + int ret = 0; + + for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++) + ret |= s1[i] ^ s2[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; +} + size_t str_match(const char *p1, const char *p2) { diff --git a/src/lib/strfuncs.h b/src/lib/strfuncs.h index bfd2bd17b3..0fef770ac8 100644 --- a/src/lib/strfuncs.h +++ b/src/lib/strfuncs.h @@ -80,6 +80,11 @@ 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); +/* Returns TRUE if the two strings are equal. Similar to + mem_equals_timing_safe() this function is safe against timing attacks when + the string lengths are the same. If not, the length of the secret string may + be leaked, but otherwise the contents won't be. */ +bool str_equals_timing_almost_safe(const char *s1, const char *s2); size_t str_match(const char *p1, const char *p2) ATTR_PURE; static inline ATTR_PURE bool str_begins(const char *haystack, const char *needle) diff --git a/src/lib/test-strfuncs.c b/src/lib/test-strfuncs.c index a2ea307376..5db2711037 100644 --- a/src/lib/test-strfuncs.c +++ b/src/lib/test-strfuncs.c @@ -387,6 +387,32 @@ static void test_mem_equals_timing_safe(void) test_end(); } +static void test_str_equals_timing_almost_safe(void) +{ + const struct { + const char *a, *b; + } tests[] = { + { "", "" }, + { "a", "a" }, + { "b", "a" }, + { "ab", "ab" }, + { "ab", "ba" }, + { "ab", "bc" }, + { "a", "" }, + { "a", "ab" }, + { "a", "abc" }, + { "ab", "abc" }, + }; + test_begin("str_equals_timing_almost_safe()"); + for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) { + test_assert((strcmp(tests[i].a, tests[i].b) == 0) == + str_equals_timing_almost_safe(tests[i].a, tests[i].b)); + test_assert((strcmp(tests[i].a, tests[i].b) == 0) == + str_equals_timing_almost_safe(tests[i].b, tests[i].a)); + } + test_end(); +} + static void test_dec2str_buf(void) { const uintmax_t test_input[] = { @@ -462,6 +488,7 @@ void test_strfuncs(void) test_t_strarray_join(); test_p_array_const_string_join(); test_mem_equals_timing_safe(); + test_str_equals_timing_almost_safe(); test_dec2str_buf(); test_str_match(); }