@@ -749,17 +749,16 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
749749 #define AESNI_ALIGN 16
750750 #endif
751751
752- /* note that all write access to these static variables must be idempotent,
753- * as arranged by Check_CPU_support_AES(), else they will be susceptible to
754- * data races.
755- */
756- static int checkedAESNI = 0;
757- static int haveAESNI = 0;
758- static cpuid_flags_t intel_flags = WC_CPUID_INITIALIZER;
752+ /* Accessed with the wolfSSL atomic APIs so the one-time detection is free of
753+ * data races. Writes are also idempotent (all callers compute the same
754+ * value), so a benign concurrent double-write is harmless. */
755+ static wolfSSL_Atomic_Uint checkedAESNI = WOLFSSL_ATOMIC_INITIALIZER(0);
756+ static wolfSSL_Atomic_Uint haveAESNI = WOLFSSL_ATOMIC_INITIALIZER(0);
757+ static cpuid_flags_atomic_t intel_flags = WC_CPUID_ATOMIC_INITIALIZER;
759758
760759 static WARN_UNUSED_RESULT int Check_CPU_support_AES(void)
761760 {
762- cpuid_get_flags_ex (&intel_flags);
761+ cpuid_get_flags_atomic (&intel_flags);
763762
764763 return IS_INTEL_AESNI(intel_flags) != 0;
765764 }
@@ -1163,11 +1162,11 @@ block cipher mechanism that uses n-bit binary string parameter key with 128-bits
11631162
11641163#elif defined(WOLFSSL_ARMASM)
11651164#if defined(__aarch64__) && !defined(WOLFSSL_ARMASM_NO_HW_CRYPTO)
1166- static cpuid_flags_t cpuid_flags = WC_CPUID_INITIALIZER ;
1165+ static cpuid_flags_atomic_t cpuid_flags = WC_CPUID_ATOMIC_INITIALIZER ;
11671166
11681167static void Check_CPU_support_HwCrypto(Aes* aes)
11691168{
1170- cpuid_get_flags_ex (&cpuid_flags);
1169+ cpuid_get_flags_atomic (&cpuid_flags);
11711170 aes->use_aes_hw_crypto = IS_AARCH64_AES(cpuid_flags);
11721171#ifdef HAVE_AESGCM
11731172 aes->use_pmull_hw_crypto = IS_AARCH64_PMULL(cpuid_flags);
@@ -1242,6 +1241,83 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(Aes* aes, const byte* inBlock,
12421241
12431242#elif (defined(WOLFSSL_PPC64_ASM) || defined(WOLFSSL_PPC32_ASM))
12441243
1244+ #if defined(WOLFSSL_PPC64_ASM) && defined(WOLFSSL_PPC64_ASM_CRYPTO)
1245+ /* POWER8+ has vector AES (vcipher/vncipher...) instructions. When built in,
1246+ * select the "_crypto" implementations at run time if the CPU supports them.
1247+ *
1248+ * A run-time flag with direct calls is used rather than a function pointer: an
1249+ * indirect call would require an ELFv1 function descriptor, whereas direct
1250+ * calls work under both the ELFv1 and ELFv2 ABIs. The dispatch is expressed as
1251+ * self-referential macros - the base name inside each macro is not re-expanded
1252+ * (C99 6.10.3.4), so it names the real base function. In a PPC build the ARM
1253+ * branches that also call these names are #if'd out, so only the live PPC call
1254+ * sites are redirected. */
1255+
1256+ /* Resolved dispatch decision (0 = base, 1 = vector-crypto), accessed with the
1257+ * wolfSSL atomic APIs so the one-time detection is free of data races. The
1258+ * master cpuid flags read by cpuid_get_flags() are themselves atomic; the write
1259+ * here is idempotent so a benign concurrent double-write is harmless. */
1260+ static wolfSSL_Atomic_Uint aes_ppc64_use_crypto = WOLFSSL_ATOMIC_INITIALIZER(0);
1261+
1262+ /* True when the CPU supports the vector-crypto instructions. */
1263+ #define AES_PPC64_USE_CRYPTO() (WOLFSSL_ATOMIC_LOAD(aes_ppc64_use_crypto) != 0)
1264+
1265+ /* Check and set the decision together (as Check_CPU_support_AES/HwCrypto do);
1266+ * called from the key-setup path before any AES_*_crypto use. */
1267+ static void Aes_SetCrypto(void)
1268+ {
1269+ WOLFSSL_ATOMIC_STORE(aes_ppc64_use_crypto,
1270+ (unsigned int)(IS_PPC64_VEC_CRYPTO(cpuid_get_flags()) != 0));
1271+ }
1272+
1273+ #define AES_set_encrypt_key(key, len, ks) \
1274+ (AES_PPC64_USE_CRYPTO() ? \
1275+ AES_set_encrypt_key_crypto((key), (len), (ks)) : \
1276+ AES_set_encrypt_key((key), (len), (ks)))
1277+ #define AES_invert_key(ks, rounds) \
1278+ (AES_PPC64_USE_CRYPTO() ? \
1279+ AES_invert_key_crypto((ks), (rounds)) : \
1280+ AES_invert_key((ks), (rounds)))
1281+ #define AES_ECB_encrypt(in, out, len, ks, nr) \
1282+ (AES_PPC64_USE_CRYPTO() ? \
1283+ AES_ECB_encrypt_crypto((in), (out), (len), (ks), (nr)) : \
1284+ AES_ECB_encrypt((in), (out), (len), (ks), (nr)))
1285+ #define AES_ECB_decrypt(in, out, len, ks, nr) \
1286+ (AES_PPC64_USE_CRYPTO() ? \
1287+ AES_ECB_decrypt_crypto((in), (out), (len), (ks), (nr)) : \
1288+ AES_ECB_decrypt((in), (out), (len), (ks), (nr)))
1289+ #define AES_CBC_encrypt(in, out, len, ks, nr, iv) \
1290+ (AES_PPC64_USE_CRYPTO() ? \
1291+ AES_CBC_encrypt_crypto((in), (out), (len), (ks), (nr), (iv)) : \
1292+ AES_CBC_encrypt((in), (out), (len), (ks), (nr), (iv)))
1293+ #define AES_CBC_decrypt(in, out, len, ks, nr, iv) \
1294+ (AES_PPC64_USE_CRYPTO() ? \
1295+ AES_CBC_decrypt_crypto((in), (out), (len), (ks), (nr), (iv)) : \
1296+ AES_CBC_decrypt((in), (out), (len), (ks), (nr), (iv)))
1297+ #define AES_CTR_encrypt(in, out, len, ks, nr, ctr) \
1298+ (AES_PPC64_USE_CRYPTO() ? \
1299+ AES_CTR_encrypt_crypto((in), (out), (len), (ks), (nr), (ctr)) : \
1300+ AES_CTR_encrypt((in), (out), (len), (ks), (nr), (ctr)))
1301+ #define AES_GCM_encrypt(in, out, len, ks, nr, ctr) \
1302+ (AES_PPC64_USE_CRYPTO() ? \
1303+ AES_GCM_encrypt_crypto((in), (out), (len), (ks), (nr), (ctr)) : \
1304+ AES_GCM_encrypt((in), (out), (len), (ks), (nr), (ctr)))
1305+ #if defined(WOLFSSL_AES_XTS)
1306+ #define AES_XTS_encrypt(in, out, sz, i, key, key2, tmp, nr) \
1307+ (AES_PPC64_USE_CRYPTO() ? \
1308+ AES_XTS_encrypt_crypto((in), (out), (sz), (i), (key), (key2), (tmp), \
1309+ (nr)) : \
1310+ AES_XTS_encrypt((in), (out), (sz), (i), (key), (key2), (tmp), (nr)))
1311+ #define AES_XTS_decrypt(in, out, sz, i, key, key2, tmp, nr) \
1312+ (AES_PPC64_USE_CRYPTO() ? \
1313+ AES_XTS_decrypt_crypto((in), (out), (sz), (i), (key), (key2), (tmp), \
1314+ (nr)) : \
1315+ AES_XTS_decrypt((in), (out), (sz), (i), (key), (key2), (tmp), (nr)))
1316+ #endif /* WOLFSSL_AES_XTS */
1317+ #else
1318+ #define Aes_SetCrypto() WC_DO_NOTHING
1319+ #endif /* WOLFSSL_PPC64_ASM && WOLFSSL_PPC64_ASM_CRYPTO */
1320+
12451321#if defined(WOLFSSL_AES_DIRECT) || defined(HAVE_AESCCM) || \
12461322 defined(WOLFSSL_AESGCM_STREAM) || defined(HAVE_AESGCM)
12471323static WARN_UNUSED_RESULT int wc_AesEncrypt(Aes* aes, const byte* inBlock,
@@ -4955,6 +5031,9 @@ static WARN_UNUSED_RESULT int wc_AesDecrypt(Aes* aes, const byte* inBlock,
49555031 aes->keylen = (int)keylen;
49565032 aes->rounds = (keylen/4) + 6;
49575033
5034+ /* Determine base vs vector-crypto before the (dispatched) key setup so
5035+ * the schedule matches the mode functions that later consume it. */
5036+ Aes_SetCrypto();
49585037 AES_set_encrypt_key(userKey, keylen * 8, (byte*)aes->key);
49595038
49605039 #ifdef HAVE_AES_DECRYPT
@@ -5637,11 +5716,11 @@ static void AesSetKey_C(Aes* aes, const byte* key, word32 keySz, int dir)
56375716 * function correctly with default build settings.
56385717 */
56395718
5640- if (checkedAESNI == 0) {
5641- haveAESNI = Check_CPU_support_AES();
5642- checkedAESNI = 1 ;
5719+ if (WOLFSSL_ATOMIC_LOAD( checkedAESNI) == 0) {
5720+ WOLFSSL_ATOMIC_STORE( haveAESNI, Check_CPU_support_AES() );
5721+ WOLFSSL_ATOMIC_STORE( checkedAESNI, 1) ;
56435722 }
5644- if (haveAESNI
5723+ if (WOLFSSL_ATOMIC_LOAD( haveAESNI)
56455724#if defined(WC_FLAG_DONT_USE_VECTOR_OPS) && !defined(WC_C_DYNAMIC_FALLBACK)
56465725 && (aes->use_aesni != WC_FLAG_DONT_USE_VECTOR_OPS)
56475726#endif
@@ -18887,7 +18966,7 @@ static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void)
1888718966static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void)
1888818967{
1888918968#ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO
18890- cpuid_get_flags_ex (&cpuid_flags);
18969+ cpuid_get_flags_atomic (&cpuid_flags);
1889118970 if (IS_AARCH64_PMULL(cpuid_flags)) {
1889218971 return &AES_GCMSIV_polyval_pmull;
1889318972 }
@@ -18906,7 +18985,7 @@ static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void)
1890618985 * AES-NI gates the base path (matching wolfSSL's AES-GCM). */
1890718986static AesGcmSivPolyvalFn AesGcmSivPolyvalAsm(void)
1890818987{
18909- cpuid_get_flags_ex (&intel_flags);
18988+ cpuid_get_flags_atomic (&intel_flags);
1891018989 if (!IS_INTEL_AESNI(intel_flags)) {
1891118990 return NULL;
1891218991 }
@@ -18951,7 +19030,7 @@ static AesGcmSivCtrFn AesGcmSivCtrAsm(void)
1895119030static AesGcmSivCtrFn AesGcmSivCtrAsm(void)
1895219031{
1895319032#ifndef WOLFSSL_ARMASM_NO_HW_CRYPTO
18954- cpuid_get_flags_ex (&cpuid_flags);
19033+ cpuid_get_flags_atomic (&cpuid_flags);
1895519034 if (IS_AARCH64_AES(cpuid_flags)) {
1895619035 return &AES_GCMSIV_ctr_aarch64;
1895719036 }
@@ -18969,7 +19048,7 @@ static AesGcmSivCtrFn AesGcmSivCtrAsm(void)
1896919048 * the base; AVX1/VAES/AVX512 are progressively wider pipelines. */
1897019049static AesGcmSivCtrFn AesGcmSivCtrAsm(void)
1897119050{
18972- cpuid_get_flags_ex (&intel_flags);
19051+ cpuid_get_flags_atomic (&intel_flags);
1897319052 if (!IS_INTEL_AESNI(intel_flags)) {
1897419053 return NULL;
1897519054 }
0 commit comments