]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Add mem_equals_timing_safe()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Sat, 8 Apr 2017 21:49:37 +0000 (00:49 +0300)
committerGitLab <gitlab@git.dovecot.net>
Tue, 11 Apr 2017 12:55:26 +0000 (15:55 +0300)
src/lib/strfuncs.c
src/lib/strfuncs.h
src/lib/test-strfuncs.c

index 19d78d9a081d78ffcb453d1e0ec0fba9c204750b..6c056ef61d4cfeeb2fe4aaaa1de32e90cc5a2de5 100644 (file)
@@ -21,6 +21,8 @@ enum _str_trim_sides {
 const unsigned char uchar_nul = '\0';
 const unsigned char *uchar_empty_ptr = { 0 };
 
+volatile int timing_safety_unoptimization;
+
 int i_snprintf(char *dest, size_t max_chars, const char *format, ...)
 {
        va_list args;
@@ -507,6 +509,21 @@ int i_strcasecmp_p(const char *const *p1, const char *const *p2)
        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, bool spaces)
 {
index d52829befecd4750de4cde5046302a00c45039db..c5ab3a58ae4cb755ff39ce4ee2a5f4ff6784eb48 100644 (file)
@@ -68,6 +68,9 @@ int null_strcasecmp(const char *s1, const char *s2) ATTR_PURE;
 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)
 {
index 8171714975f7b002647c1b440451242cc6cd8b6f..d0c773d1b6a600200dd1eaaf922bc4c7b7b7ea51 100644 (file)
@@ -229,6 +229,30 @@ static void test_p_array_const_string_join(void)
        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();
@@ -240,4 +264,5 @@ void test_strfuncs(void)
        test_t_str_rtrim();
        test_t_strarray_join();
        test_p_array_const_string_join();
+       test_mem_equals_timing_safe();
 }