// Those tests work only with Clang and Memory Sanitizer #include #include extern "C" { uint8_t ct_memcmp(const void *a, const void *b, size_t sz); } TEST(ConstantTime, CtCheck_Negative) { unsigned char a[16], b[16]; unsigned i; memset(a, 42, 16); memset(b, 42, 16); ct_poison(a, 16); for (i = 0; i < 16; i++) { ct_expect_umr(); if (a[i] != b[i]) { break; } ct_require_umr(); } ct_purify(a, 16); // Ensure buffers are not optimized-out ASSERT_EQ(a[0], b[0]); } TEST(ConstantTime, CtCheck_Positive_NoAccess) { unsigned i; char result = 0; unsigned char a[16], b[16]; memset(a, 42, sizeof(a)); memset(b, 42, sizeof(b)); ct_poison(a, 16); for (i = 0; i < 16; i++) { result |= a[i] ^ b[i]; } ct_purify(a, 16); // Purify result, to allow check that otherwise // would be not constant-time. ct_purify(&result, 1); ASSERT_EQ(result, 0); } TEST(ConstantTime, CtCheck_Negative_UseSecretAsIndex) { static const unsigned char tab[2] = {1, 0}; unsigned char a[16]; unsigned char result; memset(a, 42, sizeof(a)); ct_poison(a, 16); ct_expect_umr(); result = tab[a[0] & 1]; ct_require_umr(); ct_purify(a, 16); // Ensure variables are not optimized-out ct_purify(&result, 1); ASSERT_EQ(result, 1); } TEST(ConstantTime, CtCheck_memcmp) { unsigned char a[16], b[16]; memset(a, 42, sizeof(a)); memset(b, 42, sizeof(b)); uint8_t ret; ct_poison(a, 16); ret = ct_memcmp(a,b,16); ct_purify(&ret, 1); ASSERT_EQ(ret,0); b[1] = 0; ret = ct_memcmp(a,b,16); ct_purify(&ret, 1); ASSERT_EQ(ret,1); } TEST(ConstantTime, CtCheck_memcmp_chained) { unsigned char a[16], b[16], c[16], d[16]; memset(a, 42, sizeof(a)); memset(b, 42, sizeof(b)); memset(d, 42, sizeof(b)); memset(c, 41, sizeof(c)); uint8_t ret; ct_poison(a, 16); ct_expect_umr(); // obviously must generate UMR if if first check fails // and second is not done ret = (ct_memcmp(a,c,16)==0) && (ct_memcmp(a,b,16)==0); ct_require_umr(); ct_purify(&ret, 1); ASSERT_EQ(ret,0); ct_expect_umr(); // it's still UMR even if both checks are OK ret = (ct_memcmp(a,d,16)==0) && (ct_memcmp(a,b,16)==0); ct_require_umr(); ct_purify(&ret, 1); ASSERT_EQ(ret,1); }