lkundrak / rpms / hostapd

Forked from rpms/hostapd 4 years ago
Clone
John W. Linville aeb7fa6
From 6e34f618d37ddbb5854c42e2ad4fca83492fa7b7 Mon Sep 17 00:00:00 2001
John W. Linville aeb7fa6
From: Jouni Malinen <jouni@codeaurora.org>
John W. Linville aeb7fa6
Date: Wed, 27 Feb 2019 18:38:30 +0200
John W. Linville aeb7fa6
Subject: [PATCH 02/14] Add helper functions for constant time operations
John W. Linville aeb7fa6
John W. Linville aeb7fa6
These functions can be used to help implement constant time operations
John W. Linville aeb7fa6
for various cryptographic operations that must minimize externally
John W. Linville aeb7fa6
observable differences in processing (both in timing and also in
John W. Linville aeb7fa6
internal cache use, etc.).
John W. Linville aeb7fa6
John W. Linville aeb7fa6
This is related to CVE-2019-9494 and CVE-2019-9495.
John W. Linville aeb7fa6
John W. Linville aeb7fa6
Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
John W. Linville aeb7fa6
---
John W. Linville aeb7fa6
 src/utils/const_time.h | 191 +++++++++++++++++++++++++++++++++++++++++++++++++
John W. Linville aeb7fa6
 1 file changed, 191 insertions(+)
John W. Linville aeb7fa6
 create mode 100644 src/utils/const_time.h
John W. Linville aeb7fa6
John W. Linville aeb7fa6
diff --git a/src/utils/const_time.h b/src/utils/const_time.h
John W. Linville aeb7fa6
new file mode 100644
John W. Linville aeb7fa6
index 0000000..ab8f611
John W. Linville aeb7fa6
--- /dev/null
John W. Linville aeb7fa6
+++ b/src/utils/const_time.h
John W. Linville aeb7fa6
@@ -0,0 +1,191 @@
John W. Linville aeb7fa6
+/*
John W. Linville aeb7fa6
+ * Helper functions for constant time operations
John W. Linville aeb7fa6
+ * Copyright (c) 2019, The Linux Foundation
John W. Linville aeb7fa6
+ *
John W. Linville aeb7fa6
+ * This software may be distributed under the terms of the BSD license.
John W. Linville aeb7fa6
+ * See README for more details.
John W. Linville aeb7fa6
+ *
John W. Linville aeb7fa6
+ * These helper functions can be used to implement logic that needs to minimize
John W. Linville aeb7fa6
+ * externally visible differences in execution path by avoiding use of branches,
John W. Linville aeb7fa6
+ * avoiding early termination or other time differences, and forcing same memory
John W. Linville aeb7fa6
+ * access pattern regardless of values.
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+#ifndef CONST_TIME_H
John W. Linville aeb7fa6
+#define CONST_TIME_H
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+#if defined(__clang__)
John W. Linville aeb7fa6
+#define NO_UBSAN_UINT_OVERFLOW \
John W. Linville aeb7fa6
+	__attribute__((no_sanitize("unsigned-integer-overflow")))
John W. Linville aeb7fa6
+#else
John W. Linville aeb7fa6
+#define NO_UBSAN_UINT_OVERFLOW
John W. Linville aeb7fa6
+#endif
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/**
John W. Linville aeb7fa6
+ * const_time_fill_msb - Fill all bits with MSB value
John W. Linville aeb7fa6
+ * @val: Input value
John W. Linville aeb7fa6
+ * Returns: Value with all the bits set to the MSB of the input val
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+static inline unsigned int const_time_fill_msb(unsigned int val)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	/* Move the MSB to LSB and multiple by -1 to fill in all bits. */
John W. Linville aeb7fa6
+	return (val >> (sizeof(val) * 8 - 1)) * ~0U;
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/* Returns: -1 if val is zero; 0 if val is not zero */
John W. Linville aeb7fa6
+static inline unsigned int const_time_is_zero(unsigned int val)
John W. Linville aeb7fa6
+	NO_UBSAN_UINT_OVERFLOW
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	/* Set MSB to 1 for 0 and fill rest of bits with the MSB value */
John W. Linville aeb7fa6
+	return const_time_fill_msb(~val & (val - 1));
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/* Returns: -1 if a == b; 0 if a != b */
John W. Linville aeb7fa6
+static inline unsigned int const_time_eq(unsigned int a, unsigned int b)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	return const_time_is_zero(a ^ b);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/* Returns: -1 if a == b; 0 if a != b */
John W. Linville aeb7fa6
+static inline u8 const_time_eq_u8(unsigned int a, unsigned int b)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	return (u8) const_time_eq(a, b);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/**
John W. Linville aeb7fa6
+ * const_time_eq_bin - Constant time memory comparison
John W. Linville aeb7fa6
+ * @a: First buffer to compare
John W. Linville aeb7fa6
+ * @b: Second buffer to compare
John W. Linville aeb7fa6
+ * @len: Number of octets to compare
John W. Linville aeb7fa6
+ * Returns: -1 if buffers are equal, 0 if not
John W. Linville aeb7fa6
+ *
John W. Linville aeb7fa6
+ * This function is meant for comparing passwords or hash values where
John W. Linville aeb7fa6
+ * difference in execution time or memory access pattern could provide external
John W. Linville aeb7fa6
+ * observer information about the location of the difference in the memory
John W. Linville aeb7fa6
+ * buffers. The return value does not behave like memcmp(), i.e.,
John W. Linville aeb7fa6
+ * const_time_eq_bin() cannot be used to sort items into a defined order. Unlike
John W. Linville aeb7fa6
+ * memcmp(), the execution time of const_time_eq_bin() does not depend on the
John W. Linville aeb7fa6
+ * contents of the compared memory buffers, but only on the total compared
John W. Linville aeb7fa6
+ * length.
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+static inline unsigned int const_time_eq_bin(const void *a, const void *b,
John W. Linville aeb7fa6
+					     size_t len)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	const u8 *aa = a;
John W. Linville aeb7fa6
+	const u8 *bb = b;
John W. Linville aeb7fa6
+	size_t i;
John W. Linville aeb7fa6
+	u8 res = 0;
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+	for (i = 0; i < len; i++)
John W. Linville aeb7fa6
+		res |= aa[i] ^ bb[i];
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+	return const_time_is_zero(res);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/**
John W. Linville aeb7fa6
+ * const_time_select - Constant time unsigned int selection
John W. Linville aeb7fa6
+ * @mask: 0 (false) or -1 (true) to identify which value to select
John W. Linville aeb7fa6
+ * @true_val: Value to select for the true case
John W. Linville aeb7fa6
+ * @false_val: Value to select for the false case
John W. Linville aeb7fa6
+ * Returns: true_val if mask == -1, false_val if mask == 0
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+static inline unsigned int const_time_select(unsigned int mask,
John W. Linville aeb7fa6
+					     unsigned int true_val,
John W. Linville aeb7fa6
+					     unsigned int false_val)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	return (mask & true_val) | (~mask & false_val);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/**
John W. Linville aeb7fa6
+ * const_time_select_int - Constant time int selection
John W. Linville aeb7fa6
+ * @mask: 0 (false) or -1 (true) to identify which value to select
John W. Linville aeb7fa6
+ * @true_val: Value to select for the true case
John W. Linville aeb7fa6
+ * @false_val: Value to select for the false case
John W. Linville aeb7fa6
+ * Returns: true_val if mask == -1, false_val if mask == 0
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+static inline int const_time_select_int(unsigned int mask, int true_val,
John W. Linville aeb7fa6
+					int false_val)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	return (int) const_time_select(mask, (unsigned int) true_val,
John W. Linville aeb7fa6
+				       (unsigned int) false_val);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/**
John W. Linville aeb7fa6
+ * const_time_select_u8 - Constant time u8 selection
John W. Linville aeb7fa6
+ * @mask: 0 (false) or -1 (true) to identify which value to select
John W. Linville aeb7fa6
+ * @true_val: Value to select for the true case
John W. Linville aeb7fa6
+ * @false_val: Value to select for the false case
John W. Linville aeb7fa6
+ * Returns: true_val if mask == -1, false_val if mask == 0
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+static inline u8 const_time_select_u8(u8 mask, u8 true_val, u8 false_val)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	return (u8) const_time_select(mask, true_val, false_val);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/**
John W. Linville aeb7fa6
+ * const_time_select_s8 - Constant time s8 selection
John W. Linville aeb7fa6
+ * @mask: 0 (false) or -1 (true) to identify which value to select
John W. Linville aeb7fa6
+ * @true_val: Value to select for the true case
John W. Linville aeb7fa6
+ * @false_val: Value to select for the false case
John W. Linville aeb7fa6
+ * Returns: true_val if mask == -1, false_val if mask == 0
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+static inline s8 const_time_select_s8(u8 mask, s8 true_val, s8 false_val)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	return (s8) const_time_select(mask, (unsigned int) true_val,
John W. Linville aeb7fa6
+				      (unsigned int) false_val);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+/**
John W. Linville aeb7fa6
+ * const_time_select_bin - Constant time binary buffer selection copy
John W. Linville aeb7fa6
+ * @mask: 0 (false) or -1 (true) to identify which value to copy
John W. Linville aeb7fa6
+ * @true_val: Buffer to copy for the true case
John W. Linville aeb7fa6
+ * @false_val: Buffer to copy for the false case
John W. Linville aeb7fa6
+ * @len: Number of octets to copy
John W. Linville aeb7fa6
+ * @dst: Destination buffer for the copy
John W. Linville aeb7fa6
+ *
John W. Linville aeb7fa6
+ * This function copies the specified buffer into the destination buffer using
John W. Linville aeb7fa6
+ * operations with identical memory access pattern regardless of which buffer
John W. Linville aeb7fa6
+ * is being copied.
John W. Linville aeb7fa6
+ */
John W. Linville aeb7fa6
+static inline void const_time_select_bin(u8 mask, const u8 *true_val,
John W. Linville aeb7fa6
+					 const u8 *false_val, size_t len,
John W. Linville aeb7fa6
+					 u8 *dst)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	size_t i;
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+	for (i = 0; i < len; i++)
John W. Linville aeb7fa6
+		dst[i] = const_time_select_u8(mask, true_val[i], false_val[i]);
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+static inline int const_time_memcmp(const void *a, const void *b, size_t len)
John W. Linville aeb7fa6
+{
John W. Linville aeb7fa6
+	const u8 *aa = a;
John W. Linville aeb7fa6
+	const u8 *bb = b;
John W. Linville aeb7fa6
+	int diff, res = 0;
John W. Linville aeb7fa6
+	unsigned int mask;
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+	if (len == 0)
John W. Linville aeb7fa6
+		return 0;
John W. Linville aeb7fa6
+	do {
John W. Linville aeb7fa6
+		len--;
John W. Linville aeb7fa6
+		diff = (int) aa[len] - (int) bb[len];
John W. Linville aeb7fa6
+		mask = const_time_is_zero((unsigned int) diff);
John W. Linville aeb7fa6
+		res = const_time_select_int(mask, res, diff);
John W. Linville aeb7fa6
+	} while (len);
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+	return res;
John W. Linville aeb7fa6
+}
John W. Linville aeb7fa6
+
John W. Linville aeb7fa6
+#endif /* CONST_TIME_H */
John W. Linville aeb7fa6
-- 
John W. Linville aeb7fa6
2.7.4
John W. Linville aeb7fa6