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;
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)
{
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)
{
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();
test_t_str_rtrim();
test_t_strarray_join();
test_p_array_const_string_join();
+ test_mem_equals_timing_safe();
}