diff --git a/scripts/timeattack.c b/scripts/timeattack.c index 0a53abae9..3d7ffee7d 100644 --- a/scripts/timeattack.c +++ b/scripts/timeattack.c @@ -196,6 +196,12 @@ CALLBACK(attack_memeq4, bool, return !m; } +CALLBACK(attack_memeq5, bool, + u_char *subj, u_char *data, size_t len) +{ + return memeq_const(subj, data, len); +} + static bool attack_memeq(char *name, u_int iterations, u_int distance) { struct { @@ -206,6 +212,7 @@ static bool attack_memeq(char *name, u_int iterations, u_int distance) { "memeq2", attack_memeq2 }, { "memeq3", attack_memeq3 }, { "memeq4", attack_memeq4 }, + { "memeq5", attack_memeq5 }, }; u_char exp[16]; int i; @@ -350,7 +357,7 @@ int main(int argc, char *argv[]) if (argc < 3) { fprintf(stderr, "usage: %s \n", argv[0]); - fprintf(stderr, " : memeq[1-4] / aead / signer\n"); + fprintf(stderr, " : memeq[1-5] / aead / signer\n"); fprintf(stderr, " : number of invocations * 1000\n"); fprintf(stderr, " : time difference in ns for a hit\n"); fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]); diff --git a/src/libstrongswan/tests/suites/test_utils.c b/src/libstrongswan/tests/suites/test_utils.c index 85a854456..f151fb35e 100644 --- a/src/libstrongswan/tests/suites/test_utils.c +++ b/src/libstrongswan/tests/suites/test_utils.c @@ -306,6 +306,48 @@ START_TEST(test_memxor_aligned) } END_TEST +/******************************************************************************* + * memeq/const + */ + +static struct { + char *a; + char *b; + size_t n; + bool res; +} memeq_data[] = { + {NULL, NULL, 0, TRUE}, + {"a", "b", 0, TRUE}, + {"", "", 1, TRUE}, + {"abcdefgh", "abcdefgh", 8, TRUE}, + {"a", "b", 1, FALSE}, + {"A", "a", 1, FALSE}, + {"\0a", "\0b", 2, FALSE}, + {"abc", "abd", 3, FALSE}, + {"abc", "dbd", 3, FALSE}, + {"abcdefgh", "abcdffgh", 8, FALSE}, + {"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 52, TRUE}, + {"abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyy", 52, FALSE}, + {"bbcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", + "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz", 52, FALSE}, +}; + +START_TEST(test_memeq) +{ + ck_assert(memeq(memeq_data[_i].a, memeq_data[_i].b, + memeq_data[_i].n) == memeq_data[_i].res); +} +END_TEST + +START_TEST(test_memeq_const) +{ + ck_assert(memeq_const(memeq_data[_i].a, memeq_data[_i].b, + memeq_data[_i].n) == memeq_data[_i].res); +} +END_TEST + /******************************************************************************* * memstr */ @@ -779,6 +821,11 @@ Suite *utils_suite_create() tcase_add_test(tc, test_memxor_aligned); suite_add_tcase(s, tc); + tc = tcase_create("memeq"); + tcase_add_loop_test(tc, test_memeq, 0, countof(memeq_data)); + tcase_add_loop_test(tc, test_memeq_const, 0, countof(memeq_data)); + suite_add_tcase(s, tc); + tc = tcase_create("memstr"); tcase_add_loop_test(tc, test_memstr, 0, countof(memstr_data)); suite_add_tcase(s, tc); diff --git a/src/libstrongswan/utils/utils.c b/src/libstrongswan/utils/utils.c index 02a720945..3d5e3dfc9 100644 --- a/src/libstrongswan/utils/utils.c +++ b/src/libstrongswan/utils/utils.c @@ -109,6 +109,25 @@ void memwipe_noinline(void *ptr, size_t n) memwipe_inline(ptr, n); } +/** + * Described in header. + */ +bool memeq_const(const void *x, const void *y, size_t len) +{ + const u_char *a, *b; + u_int bad = 0; + size_t i; + + a = (const u_char*)x; + b = (const u_char*)y; + + for (i = 0; i < len; i++) + { + bad |= a[i] != b[i]; + } + return !bad; +} + /** * Described in header. */ diff --git a/src/libstrongswan/utils/utils.h b/src/libstrongswan/utils/utils.h index 7c48d949f..2675acae8 100644 --- a/src/libstrongswan/utils/utils.h +++ b/src/libstrongswan/utils/utils.h @@ -184,6 +184,11 @@ static inline bool memeq(const void *x, const void *y, size_t len) return memcmp(x, y, len) == 0; } +/** + * Same as memeq(), but with a constant runtime, safe for cryptographic use. + */ +bool memeq_const(const void *x, const void *y, size_t len); + /** * Calling memcpy() with NULL pointers, even with n == 0, results in undefined * behavior according to the C standard. This version is guaranteed to not