diff options
Diffstat (limited to 'src/lib/ctime')
-rw-r--r-- | src/lib/ctime/di_ops.c | 36 | ||||
-rw-r--r-- | src/lib/ctime/di_ops.h | 27 | ||||
-rw-r--r-- | src/lib/ctime/include.am | 2 | ||||
-rw-r--r-- | src/lib/ctime/lib_ctime.md | 14 |
4 files changed, 74 insertions, 5 deletions
diff --git a/src/lib/ctime/di_ops.c b/src/lib/ctime/di_ops.c index 89e0837ae9..d57d286990 100644 --- a/src/lib/ctime/di_ops.c +++ b/src/lib/ctime/di_ops.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2011-2019, The Tor Project, Inc. */ +/* Copyright (c) 2011-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -72,10 +72,10 @@ tor_memcmp(const void *a, const void *b, size_t len) * actually implementation-defined in standard C. So how do we * get away with assuming it? Easy. We check.) */ #if ((-60 >> 8) != -1) -#error "According to cpp, right-shift doesn't perform sign-extension." +#error "cpp says right-shift doesn't perform sign-extension." #endif #ifndef RSHIFT_DOES_SIGN_EXTEND -#error "According to configure, right-shift doesn't perform sign-extension." +#error "configure says right-shift doesn't perform sign-extension." #endif /* If v1 == v2, equal_p is ~0, so this will leave retval @@ -145,8 +145,11 @@ tor_memeq(const void *a, const void *b, size_t sz) /* Implement di_digest256_map_t as a linked list of entries. */ struct di_digest256_map_t { + /** Pointer to the next entry in the list. */ struct di_digest256_map_t *next; + /** Key for this entry. */ uint8_t key[32]; + /** Value for this entry. */ void *val; }; @@ -276,3 +279,30 @@ select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, return i_chosen; } + +/** + * If <b>s</b> is true, then copy <b>n</b> bytes from <b>src</b> to + * <b>dest</b>. Otherwise leave <b>dest</b> alone. + * + * This function behaves the same as + * + * if (s) + * memcpy(dest, src, n); + * + * except that it tries to run in the same amount of time whether <b>s</b> is + * true or not. + **/ +void +memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n) +{ + // If s is true, mask will be ~0. If s is false, mask will be 0. + const char mask = (char) -(signed char)s; + + char *destp = dest; + const char *srcp = src; + for (size_t i = 0; i < n; ++i) { + *destp = (*destp & ~mask) | (*srcp & mask); + ++destp; + ++srcp; + } +} diff --git a/src/lib/ctime/di_ops.h b/src/lib/ctime/di_ops.h index 264b56a8c1..9fe2884ecc 100644 --- a/src/lib/ctime/di_ops.h +++ b/src/lib/ctime/di_ops.h @@ -1,6 +1,6 @@ /* Copyright (c) 2003-2004, Roger Dingledine * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. - * Copyright (c) 2007-2019, The Tor Project, Inc. */ + * Copyright (c) 2007-2020, The Tor Project, Inc. */ /* See LICENSE for licensing information */ /** @@ -16,6 +16,8 @@ int tor_memcmp(const void *a, const void *b, size_t sz); int tor_memeq(const void *a, const void *b, size_t sz); +/** Perform a constant-time comparison of the <b>sz</b> bytes at <b>a</b> and + * <b>b</b>, yielding true if they are different, and false otherwise. */ #define tor_memneq(a,b,sz) (!tor_memeq((a),(b),(sz))) /** Alias for the platform's memcmp() function. This function is @@ -24,7 +26,19 @@ int tor_memeq(const void *a, const void *b, size_t sz); * implementation. */ #define fast_memcmp(a,b,c) (memcmp((a),(b),(c))) +/** Alias for the platform's memcmp() function, for use in testing equality. + * + * This function is <em>not</em> data-independent: we define this alias so + * that we can mark cases where we are deliberately using a data-dependent + * memcmp() implementation. + */ #define fast_memeq(a,b,c) (0==memcmp((a),(b),(c))) +/** Alias for the platform's memcmp() function, for use in testing inequality. + * + * This function is <em>not</em> data-independent: we define this alias so + * that we can mark cases where we are deliberately using a data-dependent + * memcmp() implementation. + */ #define fast_memneq(a,b,c) (0!=memcmp((a),(b),(c))) int safe_mem_is_zero(const void *mem, size_t sz); @@ -35,9 +49,17 @@ int safe_mem_is_zero(const void *mem, size_t sz); * * Not efficient for large maps! */ typedef struct di_digest256_map_t di_digest256_map_t; +/** + * Type for a function used to free members of a di_digest256_map_t. + **/ typedef void (*dimap_free_fn)(void *); void dimap_free_(di_digest256_map_t *map, dimap_free_fn free_fn); +/** + * @copydoc dimap_free_ + * + * Additionally, set the pointer <b>map</b> to NULL. + **/ #define dimap_free(map, free_fn) \ do { \ dimap_free_((map), (free_fn)); \ @@ -51,5 +73,6 @@ int select_array_member_cumulative_timei(const uint64_t *entries, int n_entries, uint64_t total, uint64_t rand_val); -#endif /* !defined(TOR_DI_OPS_H) */ +void memcpy_if_true_timei(bool s, void *dest, const void *src, size_t n); +#endif /* !defined(TOR_DI_OPS_H) */ diff --git a/src/lib/ctime/include.am b/src/lib/ctime/include.am index b46c43ba0c..83942ca4e0 100644 --- a/src/lib/ctime/include.am +++ b/src/lib/ctime/include.am @@ -11,6 +11,7 @@ else mulodi4_source= endif +# ADD_C_FILE: INSERT SOURCES HERE. src_lib_libtor_ctime_a_SOURCES = \ $(mulodi4_source) \ src/ext/csiphash.c \ @@ -21,5 +22,6 @@ src_lib_libtor_ctime_testing_a_SOURCES = \ src_lib_libtor_ctime_a_CFLAGS = @CFLAGS_CONSTTIME@ src_lib_libtor_ctime_testing_a_CFLAGS = @CFLAGS_CONSTTIME@ $(TEST_CFLAGS) +# ADD_C_FILE: INSERT HEADERS HERE. noinst_HEADERS += \ src/lib/ctime/di_ops.h diff --git a/src/lib/ctime/lib_ctime.md b/src/lib/ctime/lib_ctime.md new file mode 100644 index 0000000000..913199f6a5 --- /dev/null +++ b/src/lib/ctime/lib_ctime.md @@ -0,0 +1,14 @@ +@dir /lib/ctime +@brief lib/ctime: Constant-time code to avoid side-channels. + +This module contains constant-time implementations of various +data comparison and table lookup functions. We use these in preference to +memcmp() and so forth, since memcmp() can leak information about its inputs +based on how fast it returns. In general, your code should call tor_memeq() +and tor_memneq(), not memcmp(). + +We also define some _non_-constant-time wrappers for memcmp() here: Since we +consider calls to memcmp() to be in error, we require that code that actually +doesn't need to be constant-time to use the fast_memeq() / fast_memneq() / +fast_memcmp() aliases instead. + |