aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Willi <martin@revosec.ch>2015-04-11 16:44:18 +0200
committerMartin Willi <martin@revosec.ch>2015-04-14 11:51:54 +0200
commitb833963270fbffe3186f5c71c7584c2347a44038 (patch)
tree75e2d440ec3f27ca6f25b899c592e51258e21c26
parent39e1ddec2ed3480e0edc07bbabfacbf907dc4e3f (diff)
downloadstrongswan-b833963270fbffe3186f5c71c7584c2347a44038.tar.bz2
strongswan-b833963270fbffe3186f5c71c7584c2347a44038.tar.xz
utils: Add a constant time memeq() variant for cryptographic purposes
-rw-r--r--scripts/timeattack.c9
-rw-r--r--src/libstrongswan/tests/suites/test_utils.c47
-rw-r--r--src/libstrongswan/utils/utils.c19
-rw-r--r--src/libstrongswan/utils/utils.h5
4 files changed, 79 insertions, 1 deletions
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 <attack> <iterations> <distance>\n", argv[0]);
- fprintf(stderr, " <attack>: memeq[1-4] / aead / signer\n");
+ fprintf(stderr, " <attack>: memeq[1-5] / aead / signer\n");
fprintf(stderr, " <iterations>: number of invocations * 1000\n");
fprintf(stderr, " <distance>: 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
@@ -307,6 +307,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
@@ -112,6 +112,25 @@ void memwipe_noinline(void *ptr, size_t 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.
+ */
void *memstr(const void *haystack, const char *needle, size_t n)
{
const u_char *pos = haystack;
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
@@ -185,6 +185,11 @@ static inline bool memeq(const void *x, const void *y, size_t len)
}
/**
+ * 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
* access the pointers if n is 0.