AESNI: Overhaul implementation selection
Have clearly separated code to:
* determine whether the assembly-based implementation is available;
* determine whether the intrinsics-based implementation is available;
* select one of the available implementations if any.
Now MBEDTLS_AESNI_HAVE_CODE can be the single interface for aes.c and
aesni.c to determine which AESNI is built.
Change the implementation selection: now, if both implementations are
available, always prefer assembly. Before, the intrinsics were used if
available. This preference is to minimize disruption, and will likely
be revised in a later minor release.
Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/library/aes.c b/library/aes.c
index 91b6d43..69da582 100644
--- a/library/aes.c
+++ b/library/aes.c
@@ -511,7 +511,7 @@
* i.e. an offset of 1 means 4 bytes and so on.
*/
#if (defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86)) || \
- defined(MBEDTLS_HAVE_AESNI_INTRINSICS)
+ (defined(MBEDTLS_AESNI_C) && MBEDTLS_AESNI_HAVE_CODE == 2)
#define MAY_NEED_TO_ALIGN
#endif
static unsigned mbedtls_aes_rk_offset(uint32_t *buf)
@@ -528,7 +528,7 @@
}
#endif
-#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_AESNI_INTRINSICS)
+#if defined(MBEDTLS_AESNI_C) && MBEDTLS_AESNI_HAVE_CODE == 2
if (mbedtls_aesni_has_support(MBEDTLS_AESNI_AES)) {
align_16_bytes = 1;
}
diff --git a/library/aesni.c b/library/aesni.c
index e24527c..a23c5b5 100644
--- a/library/aesni.c
+++ b/library/aesni.c
@@ -30,9 +30,9 @@
#include <string.h>
-#if defined(MBEDTLS_HAVE_AESNI_INTRINSICS) || defined(MBEDTLS_HAVE_X86_64)
+#if defined(MBEDTLS_AESNI_HAVE_CODE)
-#if defined(MBEDTLS_HAVE_AESNI_INTRINSICS)
+#if MBEDTLS_AESNI_HAVE_CODE == 2
#if !defined(_WIN32)
#include <cpuid.h>
#endif
@@ -48,7 +48,7 @@
static unsigned int c = 0;
if (!done) {
-#if defined(MBEDTLS_HAVE_AESNI_INTRINSICS)
+#if MBEDTLS_AESNI_HAVE_CODE == 2
static unsigned info[4] = { 0, 0, 0, 0 };
#if defined(_MSC_VER)
__cpuid(info, 1);
@@ -56,20 +56,20 @@
__cpuid(1, info[0], info[1], info[2], info[3]);
#endif
c = info[2];
-#else
+#else /* AESNI using asm */
asm ("movl $1, %%eax \n\t"
"cpuid \n\t"
: "=c" (c)
:
: "eax", "ebx", "edx");
-#endif
+#endif /* MBEDTLS_AESNI_HAVE_CODE */
done = 1;
}
return (c & what) != 0;
}
-#if defined(MBEDTLS_HAVE_AESNI_INTRINSICS)
+#if MBEDTLS_AESNI_HAVE_CODE == 2
/*
* AES-NI AES-ECB block en(de)cryption
@@ -388,7 +388,7 @@
aesni_set_rk_256(rk[12], rk[13], _mm_aeskeygenassist_si128(rk[13], 0x40), &rk[14], &rk[15]);
}
-#else /* MBEDTLS_HAVE_AESNI_INTRINSICS */
+#else /* MBEDTLS_AESNI_HAVE_CODE == 1 */
#if defined(__has_feature)
#if __has_feature(memory_sanitizer)
@@ -776,7 +776,7 @@
: "memory", "cc", "0");
}
-#endif /* MBEDTLS_HAVE_AESNI_INTRINSICS */
+#endif /* MBEDTLS_AESNI_HAVE_CODE */
/*
* Key expansion, wrapper
@@ -795,6 +795,6 @@
return 0;
}
-#endif /* MBEDTLS_HAVE_X86_64 */
+#endif /* MBEDTLS_AESNI_HAVE_CODE */
#endif /* MBEDTLS_AESNI_C */
diff --git a/library/aesni.h b/library/aesni.h
index c1c4bdd..a81a117 100644
--- a/library/aesni.h
+++ b/library/aesni.h
@@ -32,6 +32,9 @@
#define MBEDTLS_AESNI_AES 0x02000000u
#define MBEDTLS_AESNI_CLMUL 0x00000002u
+/* Can we do AESNI with inline assembly?
+ * (Only implemented with gas syntax, only for 64-bit.)
+ */
#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && \
(defined(__amd64__) || defined(__x86_64__)) && \
!defined(MBEDTLS_HAVE_X86_64)
@@ -40,19 +43,33 @@
#if defined(MBEDTLS_AESNI_C)
-#if defined(MBEDTLS_HAVE_X86_64)
-#define MBEDTLS_AESNI_HAVE_CODE // via assembly
-#endif
-
+/* Can we do AESNI with intrinsics?
+ * (Only implemented with certain compilers, .)
+ */
+#undef MBEDTLS_AESNI_HAVE_INTRINSICS
#if defined(_MSC_VER)
-#define MBEDTLS_HAVE_AESNI_INTRINSICS
+/* Visual Studio supports AESNI intrinsics since VS 2008 SP1. We only support
+ * VS 2013 and up for other reasons anyway, so no need to check the version. */
+#define MBEDTLS_AESNI_HAVE_INTRINSICS
#endif
-#if defined(__GNUC__) && defined(__AES__)
-#define MBEDTLS_HAVE_AESNI_INTRINSICS
+/* GCC-like compilers: currently, we only support intrinsics if the requisite
+ * target flag is enabled when building the library (e.g. `gcc -mpclmul -msse2`
+ * or `clang -maes -mpclmul`). */
+#if defined(__GNUC__) && defined(__AES__) && defined(__PCLMUL__)
+#define MBEDTLS_AESNI_HAVE_INTRINSICS
#endif
-#if defined(MBEDTLS_HAVE_AESNI_INTRINSICS)
-#define MBEDTLS_AESNI_HAVE_CODE // via intrinsics
+/* Choose the implementation of AESNI, if one is available. */
+#undef MBEDTLS_AESNI_HAVE_CODE
+/* To minimize disruption when releasing the intrinsics-based implementation,
+ * favor the assembly-based implementation if it's available. We intend to
+ * revise this in a later release of Mbed TLS 3.x. In the long run, we will
+ * likely remove the assembly implementation. */
+#if defined(MBEDTLS_HAVE_X86_64)
+#define MBEDTLS_AESNI_HAVE_CODE 1 // via assembly
+#endif
+#if defined(MBEDTLS_AESNI_HAVE_INTRINSICS)
+#define MBEDTLS_AESNI_HAVE_CODE 2 // via intrinsics
#endif
#if defined(MBEDTLS_AESNI_HAVE_CODE)