Repository: randombit/botan
Pull request #3214 (2023-01-23 13:49:03)

Fix FFI when SRP6 is disabled in the build


Patch:
diff --git a/configure.py b/configure.py
index 04ca998e3..0c878336d 100755
--- a/configure.py
+++ b/configure.py
@@ -2547,12 +2547,6 @@ class ModulesChooser:
                 self._to_load.remove('compression')
                 self._not_using_because['no enabled compression schemes'].add('compression')
 
-        # The AVX2 implementation of Argon2 fails when compiled by GCC in
-        # amalgamation mode.
-        if 'argon2_avx2' in self._to_load and self._options.amalgamation and self._options.compiler == 'gcc':
-            self._to_load.remove('argon2_avx2')
-            self._not_using_because['disabled due to compiler bug'].add('argon2_avx2')
-
         self._resolve_dependencies_for_all_modules()
 
         for not_a_dep in self._maybe_dep:
@@ -2660,7 +2654,7 @@ class AmalgamationHelper:
     def write_banner(fd):
         fd.write("""/*
 * Botan %s Amalgamation
-* (C) 1999-2023 The Botan Authors
+* (C) 1999-2020 The Botan Authors
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
diff --git a/readme.rst b/readme.rst
index 358ebfc9f..a4f2fb641 100644
--- a/readme.rst
+++ b/readme.rst
@@ -66,7 +66,7 @@ Find Enclosed
 Transport Layer Security (TLS) Protocol
 ----------------------------------------
 
-* TLS v1.2/v1.3, and DTLS v1.2
+* TLS v1.2 and DTLS v1.2
 * Supported extensions include session tickets, SNI, ALPN, OCSP stapling,
   encrypt-then-mac CBC, and extended master secret.
 * Supports authentication using certificates or preshared keys (PSK)
@@ -90,7 +90,7 @@ Public Key Cryptography
 * RSA signatures and encryption
 * DH and ECDH key agreement
 * Signature schemes ECDSA, DSA, Ed25519, ECGDSA, ECKCDSA, SM2, GOST 34.10
-* Post-quantum signature schemes Dilithium and XMSS
+* Post-quantum signature scheme XMSS
 * Post-quantum key agreement schemes McEliece and Kyber
 * ElGamal encryption
 * Padding schemes OAEP, PSS, PKCS #1 v1.5, X9.31
@@ -105,7 +105,6 @@ Ciphers, hashes, MACs, and checksums
 * Stream ciphers (X)ChaCha20, (X)Salsa20, SHAKE-128, RC4
 * Hash functions SHA-1, SHA-2, SHA-3, MD5, RIPEMD-160, BLAKE2b,
   Skein-512, SM3, Streebog, Whirlpool
-* Password hashing schemes PBKDF2, Argon2, Scrypt, bcrypt
 * Authentication codes HMAC, CMAC, Poly1305, SipHash, GMAC, X9.19 DES-MAC
 * Non-cryptographic checksums Adler32, CRC24, CRC32
 
@@ -117,6 +116,7 @@ Other Useful Things
 * Simple compression API wrapping zlib, bzip2, and lzma libraries
 * RNG wrappers for system RNG and hardware RNGs
 * HMAC_DRBG and entropy collection system for userspace RNGs
+* Password hashing schemes PBKDF2, Argon2, Scrypt, bcrypt
 * SRP-6a password authenticated key exchange
 * Key derivation functions including HKDF, KDF2, SP 800-108, SP 800-56A, SP 800-56C
 * HOTP and TOTP algorithms
diff --git a/src/lib/ffi/ffi_srp6.cpp b/src/lib/ffi/ffi_srp6.cpp
index 9245c6ca4..bcf9de37c 100644
--- a/src/lib/ffi/ffi_srp6.cpp
+++ b/src/lib/ffi/ffi_srp6.cpp
@@ -1,156 +1,191 @@
 /*
 * (C) 2022 Rostyslav Khudolii
+*     2023 Jack Lloyd
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
 
 #include <botan/ffi.h>
-#include <botan/bigint.h>
 #include <botan/internal/ffi_rng.h>
 #include <botan/internal/ffi_util.h>
-#include <botan/rng.h>
-#include <botan/srp6.h>
-#include <botan/symkey.h>
+
+#if defined(BOTAN_HAS_SRP6)
+  #include <botan/bigint.h>
+  #include <botan/rng.h>
+  #include <botan/srp6.h>
+  #include <botan/symkey.h>
+#endif
 
 extern "C" {
 
-   using namespace Botan_FFI;
+using namespace Botan_FFI;
 
-   BOTAN_FFI_DECLARE_STRUCT(botan_srp6_server_session_struct,
-                            Botan::SRP6_Server_Session, 0x44F7425F);
+#if defined(BOTAN_HAS_SRP6)
+BOTAN_FFI_DECLARE_STRUCT(botan_srp6_server_session_struct,
+                         Botan::SRP6_Server_Session, 0x44F7425F);
+#else
+BOTAN_FFI_DECLARE_DUMMY_STRUCT(botan_srp6_server_session_struct, 0x44F7425F);
+#endif
 
-   int botan_srp6_server_session_init(botan_srp6_server_session_t* srp6)
+int botan_srp6_server_session_init(botan_srp6_server_session_t* srp6)
+   {
+#if defined(BOTAN_HAS_SRP6)
+   return ffi_guard_thunk(__func__, [=]() -> int
       {
-      return ffi_guard_thunk(__func__, [=]() -> int
-         {
-         *srp6 = new botan_srp6_server_session_struct(
-            std::make_unique<Botan::SRP6_Server_Session>());
-         return BOTAN_FFI_SUCCESS;
-         });
-      }
+      *srp6 = new botan_srp6_server_session_struct(
+         std::make_unique<Botan::SRP6_Server_Session>());
+      return BOTAN_FFI_SUCCESS;
+      });
+#else
+   BOTAN_UNUSED(srp6);
+   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+   }
 
-   int botan_srp6_server_session_destroy(botan_srp6_server_session_t srp6)
-      {
-      return BOTAN_FFI_CHECKED_DELETE(srp6);
-      }
+int botan_srp6_server_session_destroy(botan_srp6_server_session_t srp6)
+   {
+   return BOTAN_FFI_CHECKED_DELETE(srp6);
+   }
 
-   int botan_srp6_server_session_step1(botan_srp6_server_session_t srp6,
-                                       const uint8_t* verifier,
-                                       size_t verifier_len, const char* group_id,
-                                       const char* hash_id, botan_rng_t rng_obj,
-                                       uint8_t b_pub[], size_t* b_pub_len)
+int botan_srp6_server_session_step1(botan_srp6_server_session_t srp6,
+                                    const uint8_t* verifier,
+                                    size_t verifier_len, const char* group_id,
+                                    const char* hash_id, botan_rng_t rng_obj,
+                                    uint8_t b_pub[], size_t* b_pub_len)
+   {
+#if defined(BOTAN_HAS_SRP6)
+   return BOTAN_FFI_VISIT(srp6, [=](auto& s) -> int
       {
-      return BOTAN_FFI_VISIT(srp6, [=](auto& s) -> int
+      if(!verifier || !group_id || !hash_id || !rng_obj)
          {
-         if(!verifier || !group_id || !hash_id || !rng_obj)
-            {
-            return BOTAN_FFI_ERROR_NULL_POINTER;
-            }
-         try
-            {
-            Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
-            auto v_bn = Botan::BigInt::decode(verifier, verifier_len);
-            auto b_pub_bn = s.step1(v_bn, group_id, hash_id, rng);
-            return write_vec_output(b_pub, b_pub_len,
-                                    Botan::BigInt::encode(b_pub_bn));
-            }
-         catch(Botan::Decoding_Error&)
-            {
-            return BOTAN_FFI_ERROR_BAD_PARAMETER;
-            }
-         catch(Botan::Lookup_Error&)
-            {
-            return BOTAN_FFI_ERROR_BAD_PARAMETER;
-            }
-         });
-      }
+         return BOTAN_FFI_ERROR_NULL_POINTER;
+         }
+      try
+         {
+         Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+         auto v_bn = Botan::BigInt::decode(verifier, verifier_len);
+         auto b_pub_bn = s.step1(v_bn, group_id, hash_id, rng);
+         return write_vec_output(b_pub, b_pub_len,
+                                 Botan::BigInt::encode(b_pub_bn));
+         }
+      catch(Botan::Decoding_Error&)
+         {
+         return BOTAN_FFI_ERROR_BAD_PARAMETER;
+         }
+      catch(Botan::Lookup_Error&)
+         {
+         return BOTAN_FFI_ERROR_BAD_PARAMETER;
+         }
+      });
+#else
+   BOTAN_UNUSED(srp6, verifier, verifier_len, group_id, hash_id, rng_obj, b_pub, b_pub_len);
+   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+   }
 
-   int botan_srp6_server_session_step2(botan_srp6_server_session_t srp6,
-                                       const uint8_t a[], size_t a_len,
-                                       uint8_t key[], size_t* key_len)
+int botan_srp6_server_session_step2(botan_srp6_server_session_t srp6,
+                                    const uint8_t a[], size_t a_len,
+                                    uint8_t key[], size_t* key_len)
+   {
+#if defined(BOTAN_HAS_SRP6)
+   return BOTAN_FFI_VISIT(srp6, [=](auto& s) -> int
       {
-      return BOTAN_FFI_VISIT(srp6, [=](auto& s) -> int
+      if(!a)
          {
-         if(!a)
-            {
-            return BOTAN_FFI_ERROR_NULL_POINTER;
-            }
-         try
-            {
-            Botan::BigInt a_bn = Botan::BigInt::decode(a, a_len);
-            auto key_sk = s.step2(a_bn);
-            return write_vec_output(key, key_len, key_sk.bits_of());
-            }
-         catch(Botan::Decoding_Error&)
-            {
-            return BOTAN_FFI_ERROR_BAD_PARAMETER;
-            }
-         });
-      }
+         return BOTAN_FFI_ERROR_NULL_POINTER;
+         }
+      try
+         {
+         Botan::BigInt a_bn = Botan::BigInt::decode(a, a_len);
+         auto key_sk = s.step2(a_bn);
+         return write_vec_output(key, key_len, key_sk.bits_of());
+         }
+      catch(Botan::Decoding_Error&)
+         {
+         return BOTAN_FFI_ERROR_BAD_PARAMETER;
+         }
+      });
+#else
+   BOTAN_UNUSED(srp6, a, a_len, key, key_len);
+   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+   }
 
-   int botan_generate_srp6_verifier(const char* username, const char* password,
-                                    const uint8_t salt[], size_t salt_len,
-                                    const char* group_id, const char* hash_id,
-                                    uint8_t verifier[], size_t* verifier_len)
+int botan_generate_srp6_verifier(const char* username, const char* password,
+                                 const uint8_t salt[], size_t salt_len,
+                                 const char* group_id, const char* hash_id,
+                                 uint8_t verifier[], size_t* verifier_len)
+   {
+#if defined(BOTAN_HAS_SRP6)
+   return ffi_guard_thunk(__func__, [=]() -> int
       {
-      return ffi_guard_thunk(__func__, [=]() -> int
+      if(!username || !password || !salt || !group_id || !hash_id)
          {
-         if(!username || !password || !salt || !group_id || !hash_id)
-            {
-            return BOTAN_FFI_ERROR_NULL_POINTER;
-            }
-         try
-            {
-            std::vector<uint8_t> salt_vec(salt, salt + salt_len);
-            auto verifier_bn = Botan::generate_srp6_verifier(
-               username, password, salt_vec, group_id, hash_id);
-            return write_vec_output(verifier, verifier_len,
-                                    Botan::BigInt::encode(verifier_bn));
-            }
-         catch(Botan::Lookup_Error&)
-            {
-            return BOTAN_FFI_ERROR_BAD_PARAMETER;
-            }
-         });
-      }
+         return BOTAN_FFI_ERROR_NULL_POINTER;
+         }
+      try
+         {
+         std::vector<uint8_t> salt_vec(salt, salt + salt_len);
+         auto verifier_bn = Botan::generate_srp6_verifier(
+            username, password, salt_vec, group_id, hash_id);
+         return write_vec_output(verifier, verifier_len,
+                                 Botan::BigInt::encode(verifier_bn));
+         }
+      catch(Botan::Lookup_Error&)
+         {
+         return BOTAN_FFI_ERROR_BAD_PARAMETER;
+         }
+      });
+#else
+   BOTAN_UNUSED(username, password, group_id, hash_id);
+   BOTAN_UNUSED(salt, salt_len, verifier, verifier_len);
+   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
+   }
 
-   int botan_srp6_client_agree(const char* identity, const char* password,
-                               const char* group_id, const char* hash_id,
-                               const uint8_t salt[], size_t salt_len,
-                               const uint8_t b[], size_t b_len, botan_rng_t rng_obj,
-                               uint8_t A[], size_t* A_len, uint8_t K[],
-                               size_t* K_len)
+int botan_srp6_client_agree(const char* identity, const char* password,
+                            const char* group_id, const char* hash_id,
+                            const uint8_t salt[], size_t salt_len,
+                            const uint8_t b[], size_t b_len, botan_rng_t rng_obj,
+                            uint8_t A[], size_t* A_len, uint8_t K[],
+                            size_t* K_len)
+   {
+#if defined(BOTAN_HAS_SRP6)
+   return ffi_guard_thunk(__func__, [=]() -> int
       {
-      return ffi_guard_thunk(__func__, [=]() -> int
+      if(!identity || !password || !salt || !group_id || !hash_id || !b || !rng_obj)
          {
-         if(!identity || !password || !salt || !group_id || !hash_id || !b || !rng_obj)
-            {
-            return BOTAN_FFI_ERROR_NULL_POINTER;
-            }
-         try
+         return BOTAN_FFI_ERROR_NULL_POINTER;
+         }
+      try
+         {
+         std::vector<uint8_t> saltv(salt, salt + salt_len);
+         Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
+         auto b_bn = Botan::BigInt::decode(b, b_len);
+         auto [A_bn, K_sk] = Botan::srp6_client_agree(
+            identity, password, group_id, hash_id, saltv, b_bn, rng);
+         auto ret_a = write_vec_output(A, A_len, Botan::BigInt::encode(A_bn));
+         auto ret_k = write_vec_output(K, K_len, K_sk.bits_of());
+         if(ret_a != BOTAN_FFI_SUCCESS)
             {
-            std::vector<uint8_t> saltv(salt, salt + salt_len);
-            Botan::RandomNumberGenerator& rng = safe_get(rng_obj);
-            auto b_bn = Botan::BigInt::decode(b, b_len);
-            auto [A_bn, K_sk] = Botan::srp6_client_agree(
-               identity, password, group_id, hash_id, saltv, b_bn, rng);
-            auto ret_a = write_vec_output(A, A_len, Botan::BigInt::encode(A_bn));
-            auto ret_k = write_vec_output(K, K_len, K_sk.bits_of());
-            if(ret_a != BOTAN_FFI_SUCCESS)
-               {
-               return ret_a;
-               }
-            if(ret_k != BOTAN_FFI_SUCCESS)
-               {
-               return ret_k;
-               }
-            return BOTAN_FFI_SUCCESS;
+            return ret_a;
             }
-         catch(Botan::Lookup_Error&)
+         if(ret_k != BOTAN_FFI_SUCCESS)
             {
-            return BOTAN_FFI_ERROR_BAD_PARAMETER;
+            return ret_k;
             }
-         });
-      }
-
+         return BOTAN_FFI_SUCCESS;
+         }
+      catch(Botan::Lookup_Error&)
+         {
+         return BOTAN_FFI_ERROR_BAD_PARAMETER;
+         }
+      });
+#else
+   BOTAN_UNUSED(identity, password, group_id, hash_id, rng_obj);
+   BOTAN_UNUSED(salt, salt_len, b, b_len, A, A_len, K, K_len);
+   return BOTAN_FFI_ERROR_NOT_IMPLEMENTED;
+#endif
    }
+
+}
diff --git a/src/lib/ffi/ffi_util.h b/src/lib/ffi/ffi_util.h
index bc9884713..11a1d6839 100644
--- a/src/lib/ffi/ffi_util.h
+++ b/src/lib/ffi/ffi_util.h
@@ -57,6 +57,10 @@ struct botan_struct
       explicit NAME(std::unique_ptr<TYPE> x) : botan_struct(std::move(x)) {} \
    }
 
+#define BOTAN_FFI_DECLARE_DUMMY_STRUCT(NAME, MAGIC)                          \
+   struct NAME final : public Botan_FFI::botan_struct<int, MAGIC> {          \
+   }
+
 // Declared in ffi.cpp
 int ffi_error_exception_thrown(const char* func_name, const char* exn,
                                int rc = BOTAN_FFI_ERROR_EXCEPTION_THROWN);
diff --git a/src/lib/filters/threaded_fork.cpp b/src/lib/filters/threaded_fork.cpp
index 16206bfa2..07b2805ff 100644
--- a/src/lib/filters/threaded_fork.cpp
+++ b/src/lib/filters/threaded_fork.cpp
@@ -10,19 +10,20 @@
 
 #if defined(BOTAN_HAS_THREAD_UTILS)
 
-#include <botan/internal/semaphore.h>
 #include <botan/internal/barrier.h>
 #include <functional>
+#include <semaphore>
 
 namespace Botan {
 
 struct Threaded_Fork_Data
    {
+   static constexpr size_t max_filters = 1024;
    /*
    * Semaphore for indicating that there is work to be done (or to
    * quit)
    */
-   Semaphore m_input_ready_semaphore;
+   std::counting_semaphore<max_filters> m_input_ready_semaphore{0};
 
    /*
    * Synchronises all threads to complete processing data in lock-step.
@@ -60,6 +61,10 @@ Threaded_Fork::Threaded_Fork(Filter* filters[], size_t count) :
    Fork(nullptr, static_cast<size_t>(0)),
    m_thread_data(new Threaded_Fork_Data)
    {
+   if (count > Threaded_Fork_Data::max_filters)
+      {
+      throw Invalid_Argument("count exceeds the max filters supported");
+      }
    set_next(filters, count);
    }
 
diff --git a/src/lib/pbkdf/argon2/argon2.cpp b/src/lib/pbkdf/argon2/argon2.cpp
index 05d896800..3555a9a93 100644
--- a/src/lib/pbkdf/argon2/argon2.cpp
+++ b/src/lib/pbkdf/argon2/argon2.cpp
@@ -15,7 +15,8 @@
    #include <botan/internal/thread_pool.h>
 #endif
 
-#if defined(BOTAN_HAS_ARGON2_AVX2) || defined(BOTAN_HAS_ARGON2_SSSE3)
+#if defined(BOTAN_HAS_ARGON2_SSSE3)
+   #include <botan/internal/argon2_ssse3.h>
    #include <botan/internal/cpuid.h>
 #endif
 
@@ -173,22 +174,13 @@ BOTAN_FORCE_INLINE void blamka_G(uint64_t& A, uint64_t& B, uint64_t& C, uint64_t
    B = rotr<63>(B ^ C);
    }
 
-}
-
-void Argon2::blamka(uint64_t N[128], uint64_t T[128])
+void blamka(uint64_t T[128])
    {
-#if defined(BOTAN_HAS_ARGON2_AVX2)
-   if(CPUID::has_avx2())
-      return Argon2::blamka_avx2(N, T);
-#endif
-
 #if defined(BOTAN_HAS_ARGON2_SSSE3)
    if(CPUID::has_ssse3())
-      return Argon2::blamka_ssse3(N, T);
+      return blamka_ssse3(T);
 #endif
 
-   copy_mem(T, N, 128);
-
    for(size_t i = 0; i != 128; i += 16)
       {
       blamka_G(T[i+  0], T[i+  4], T[i+  8], T[i+ 12]);
@@ -214,13 +206,8 @@ void Argon2::blamka(uint64_t N[128], uint64_t T[128])
       blamka_G(T[i+ 16], T[i+ 49], T[i+ 64], T[i+ 97]);
       blamka_G(T[i+ 17], T[i+ 32], T[i+ 65], T[i+112]);
       }
-
-   for(size_t i = 0; i != 128; ++i)
-      N[i] ^= T[i];
    }
 
-namespace {
-
 void gen_2i_addresses(uint64_t T[128], uint64_t B[128],
                       size_t n, size_t lane, size_t slice, size_t memory,
                       size_t time, size_t mode, size_t cnt)
@@ -237,7 +224,12 @@ void gen_2i_addresses(uint64_t T[128], uint64_t B[128],
 
    for(size_t r = 0; r != 2; ++r)
       {
-      Argon2::blamka(B, T);
+      copy_mem(T, B, 128);
+
+      blamka(T);
+
+      for(size_t i = 0; i != 128; ++i)
+         B[i] ^= T[i];
       }
    }
 
@@ -316,14 +308,13 @@ void process_block(secure_vector<uint64_t>& B,
       const uint64_t random = use_2i ? addresses[index % 128] : B.at(128*prev);
       const size_t new_offset = index_alpha(random, lanes, segments, threads, n, slice, lane, index);
 
-      uint64_t N[128];
       for(size_t i = 0; i != 128; ++i)
-         N[i] = B[128*prev+i] ^ B[128*new_offset+i];
+         T[i] = B[128*prev+i] ^ B[128*new_offset+i];
 
-      Argon2::blamka(N, T);
+      blamka(T);
 
       for(size_t i = 0; i != 128; ++i)
-         B[128*offset + i] ^= N[i];
+         B[128*offset + i] ^= T[i] ^ B[128*prev+i] ^ B[128*new_offset+i];
 
       index += 1;
       }
diff --git a/src/lib/pbkdf/argon2/argon2.h b/src/lib/pbkdf/argon2/argon2.h
index 25833e9e3..409eec13d 100644
--- a/src/lib/pbkdf/argon2/argon2.h
+++ b/src/lib/pbkdf/argon2/argon2.h
@@ -58,18 +58,7 @@ class BOTAN_PUBLIC_API(2,11) Argon2 final : public PasswordHash
 
       size_t total_memory_usage() const override { return M() * 1024; }
 
-      /**
-      * Argon2's BLAMKA function
-      */
-      static void blamka(uint64_t N[128], uint64_t T[128]);
    private:
-#if defined(BOTAN_HAS_ARGON2_AVX2)
-      static void blamka_avx2(uint64_t N[128], uint64_t T[128]);
-#endif
-
-#if defined(BOTAN_HAS_ARGON2_SSSE3)
-      static void blamka_ssse3(uint64_t N[128], uint64_t T[128]);
-#endif
 
       void argon2(uint8_t output[], size_t output_len,
                   const char* password, size_t password_len,
diff --git a/src/lib/pbkdf/argon2/argon2_avx2/argon2_avx2.cpp b/src/lib/pbkdf/argon2/argon2_avx2/argon2_avx2.cpp
deleted file mode 100644
index 43b0fe5c1..000000000
--- a/src/lib/pbkdf/argon2/argon2_avx2/argon2_avx2.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/**
-* (C) 2023 Jack Lloyd
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/argon2.h>
-#include <immintrin.h>
-
-namespace Botan {
-
-namespace {
-
-class SIMD_4x64 final
-   {
-   public:
-      SIMD_4x64& operator=(const SIMD_4x64& other) = default;
-      SIMD_4x64(const SIMD_4x64& other) = default;
-
-      SIMD_4x64& operator=(SIMD_4x64&& other) = default;
-      SIMD_4x64(SIMD_4x64&& other) = default;
-
-      BOTAN_FUNC_ISA("avx2")
-      SIMD_4x64() // zero initialized
-         {
-         m_simd = _mm256_setzero_si256();
-         }
-
-      // Load two halves at different addresses
-      static BOTAN_FUNC_ISA("avx2")
-      SIMD_4x64 load_le2(const void* inl, const void* inh)
-         {
-         return SIMD_4x64(_mm256_loadu2_m128i(
-                             reinterpret_cast<const __m128i*>(inl),
-                             reinterpret_cast<const __m128i*>(inh)));
-         }
-
-      static BOTAN_FUNC_ISA("avx2")
-      SIMD_4x64 load_le(const void* in)
-         {
-         return SIMD_4x64(_mm256_loadu_si256(reinterpret_cast<const __m256i*>(in)));
-         }
-
-      void store_le(uint64_t out[4]) const
-         {
-         this->store_le(reinterpret_cast<uint8_t*>(out));
-         }
-
-      BOTAN_FUNC_ISA("avx2")
-      void store_le(uint8_t out[]) const
-         {
-         _mm256_storeu_si256(reinterpret_cast<__m256i*>(out), m_simd);
-         }
-
-      BOTAN_FUNC_ISA("avx2")
-      void store_le2(void* outh, void* outl)
-         {
-         _mm256_storeu2_m128i(
-            reinterpret_cast<__m128i*>(outh),
-            reinterpret_cast<__m128i*>(outl),
-            m_simd);
-         }
-
-      SIMD_4x64 operator+(const SIMD_4x64& other) const
-         {
-         SIMD_4x64 retval(*this);
-         retval += other;
-         return retval;
-         }
-
-      SIMD_4x64 operator^(const SIMD_4x64& other) const
-         {
-         SIMD_4x64 retval(*this);
-         retval ^= other;
-         return retval;
-         }
-
-      BOTAN_FUNC_ISA("avx2")
-      void operator+=(const SIMD_4x64& other)
-         {
-         m_simd = _mm256_add_epi64(m_simd, other.m_simd);
-         }
-
-      BOTAN_FUNC_ISA("avx2")
-      void operator^=(const SIMD_4x64& other)
-         {
-         m_simd = _mm256_xor_si256(m_simd, other.m_simd);
-         }
-
-      template<size_t ROT>
-      BOTAN_FUNC_ISA("avx2")
-      SIMD_4x64 rotr() const
-         {
-         static_assert(ROT > 0 && ROT < 64, "Invalid rotation constant");
-
-         if constexpr(ROT == 16)
-            {
-            auto tab = _mm256_setr_epi8(
-               2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9,
-               2, 3, 4, 5, 6, 7, 0, 1, 10, 11, 12, 13, 14, 15, 8, 9);
-            return SIMD_4x64(_mm256_shuffle_epi8(m_simd, tab));
-            }
-         else if constexpr(ROT == 24)
-            {
-            auto tab = _mm256_setr_epi8(
-               3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10,
-               3, 4, 5, 6, 7, 0, 1, 2, 11, 12, 13, 14, 15, 8, 9, 10);
-            return SIMD_4x64(_mm256_shuffle_epi8(m_simd, tab));
-         }
-         else if constexpr(ROT == 32)
-            {
-            auto tab = _mm256_setr_epi8(
-               4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11,
-               4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11);
-            return SIMD_4x64(_mm256_shuffle_epi8(m_simd, tab));
-            }
-         else
-            {
-            return SIMD_4x64(_mm256_or_si256(_mm256_srli_epi64(m_simd, static_cast<int>(ROT)),
-                                             _mm256_slli_epi64(m_simd, static_cast<int>(64-ROT))));
-            }
-         }
-
-      template<size_t ROT>
-      SIMD_4x64 rotl() const
-         {
-         return this->rotr<64-ROT>();
-         }
-
-      // Argon2 specific operation
-      static BOTAN_FUNC_ISA("avx2")
-      SIMD_4x64 mul2_32(SIMD_4x64 x, SIMD_4x64 y)
-         {
-         const __m256i m = _mm256_mul_epu32(x.m_simd, y.m_simd);
-         return SIMD_4x64(_mm256_add_epi64(m, m));
-         }
-
-      template<uint8_t CTRL>
-      static BOTAN_FUNC_ISA("avx2") SIMD_4x64 permute_4x64(SIMD_4x64 x)
-         {
-         return SIMD_4x64(_mm256_permute4x64_epi64(x.m_simd, CTRL));
-         }
-
-      // Argon2 specific
-      static void twist(
-         SIMD_4x64& B,
-         SIMD_4x64& C,
-         SIMD_4x64& D)
-         {
-         B = SIMD_4x64::permute_4x64<0b00'11'10'01>(B);
-         C = SIMD_4x64::permute_4x64<0b01'00'11'10>(C);
-         D = SIMD_4x64::permute_4x64<0b10'01'00'11>(D);
-         }
-
-      // Argon2 specific
-      static void untwist(
-         SIMD_4x64& B,
-         SIMD_4x64& C,
-         SIMD_4x64& D)
-         {
-         B = SIMD_4x64::permute_4x64<0b10'01'00'11>(B);
-         C = SIMD_4x64::permute_4x64<0b01'00'11'10>(C);
-         D = SIMD_4x64::permute_4x64<0b00'11'10'01>(D);
-         }
-
-      explicit BOTAN_FUNC_ISA("avx2") SIMD_4x64(__m256i x) : m_simd(x) {}
-   private:
-      __m256i m_simd;
-   };
-
-BOTAN_FORCE_INLINE void blamka_G(
-   SIMD_4x64& A,
-   SIMD_4x64& B,
-   SIMD_4x64& C,
-   SIMD_4x64& D)
-   {
-   A += B + SIMD_4x64::mul2_32(A, B);
-   D ^= A;
-   D = D.rotr<32>();
-
-   C += D + SIMD_4x64::mul2_32(C, D);
-   B ^= C;
-   B = B.rotr<24>();
-
-   A += B + SIMD_4x64::mul2_32(A, B);
-   D ^= A;
-   D = D.rotr<16>();
-
-   C += D + SIMD_4x64::mul2_32(C, D);
-   B ^= C;
-   B = B.rotr<63>();
-   }
-
-BOTAN_FORCE_INLINE void blamka_R(
-   SIMD_4x64& A,
-   SIMD_4x64& B,
-   SIMD_4x64& C,
-   SIMD_4x64& D)
-   {
-   blamka_G(A, B, C, D);
-
-   SIMD_4x64::twist(B, C, D);
-   blamka_G(A, B, C, D);
-   SIMD_4x64::untwist(B, C, D);
-   }
-
-}
-
-BOTAN_FUNC_ISA("avx2")
-void Argon2::blamka_avx2(uint64_t N[128], uint64_t T[128])
-   {
-   for(size_t i = 0; i != 8; ++i)
-      {
-      SIMD_4x64 A = SIMD_4x64::load_le(&N[16*i + 4*0]);
-      SIMD_4x64 B = SIMD_4x64::load_le(&N[16*i + 4*1]);
-      SIMD_4x64 C = SIMD_4x64::load_le(&N[16*i + 4*2]);
-      SIMD_4x64 D = SIMD_4x64::load_le(&N[16*i + 4*3]);
-
-      blamka_R(A, B, C, D);
-
-      A.store_le(&T[16*i + 4*0]);
-      B.store_le(&T[16*i + 4*1]);
-      C.store_le(&T[16*i + 4*2]);
-      D.store_le(&T[16*i + 4*3]);
-      }
-
-   for(size_t i = 0; i != 8; ++i)
-      {
-      SIMD_4x64 A = SIMD_4x64::load_le2(&T[2*i + 32*0], &T[2*i + 32*0 + 16]);
-      SIMD_4x64 B = SIMD_4x64::load_le2(&T[2*i + 32*1], &T[2*i + 32*1 + 16]);
-      SIMD_4x64 C = SIMD_4x64::load_le2(&T[2*i + 32*2], &T[2*i + 32*2 + 16]);
-      SIMD_4x64 D = SIMD_4x64::load_le2(&T[2*i + 32*3], &T[2*i + 32*3 + 16]);
-
-      blamka_R(A, B, C, D);
-
-      A.store_le2(&T[2*i + 32*0], &T[2*i + 32*0 + 16]);
-      B.store_le2(&T[2*i + 32*1], &T[2*i + 32*1 + 16]);
-      C.store_le2(&T[2*i + 32*2], &T[2*i + 32*2 + 16]);
-      D.store_le2(&T[2*i + 32*3], &T[2*i + 32*3 + 16]);
-      }
-
-   for(size_t i = 0; i != 128 / 8; ++i)
-      {
-      SIMD_4x64 n0 = SIMD_4x64::load_le(&N[8*i]);
-      SIMD_4x64 n1 = SIMD_4x64::load_le(&N[8*i+4]);
-      SIMD_4x64 t0 = SIMD_4x64::load_le(&T[8*i]);
-      SIMD_4x64 t1 = SIMD_4x64::load_le(&T[8*i+4]);
-
-      n0 ^= t0;
-      n1 ^= t1;
-      n0.store_le(&N[8*i]);
-      n1.store_le(&N[8*i+4]);
-      }
-   }
-
-}
diff --git a/src/lib/pbkdf/argon2/argon2_avx2/info.txt b/src/lib/pbkdf/argon2/argon2_avx2/info.txt
deleted file mode 100644
index 6c412a4b2..000000000
--- a/src/lib/pbkdf/argon2/argon2_avx2/info.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-<defines>
-ARGON2_AVX2 -> 20221216
-</defines>
-
-<module_info>
-name -> "Argon2 AVX2"
-brief -> "Argon2 using AVX2 instructions"
-</module_info>
-
-<isa>
-avx2
-</isa>
diff --git a/src/lib/pbkdf/argon2/argon2_ssse3/argon2_ssse3.cpp b/src/lib/pbkdf/argon2/argon2_ssse3/argon2_ssse3.cpp
index 3b2159628..382ba3aa5 100644
--- a/src/lib/pbkdf/argon2/argon2_ssse3/argon2_ssse3.cpp
+++ b/src/lib/pbkdf/argon2/argon2_ssse3/argon2_ssse3.cpp
@@ -4,7 +4,7 @@
 * Botan is released under the Simplified BSD License (see license.txt)
 */
 
-#include <botan/argon2.h>
+#include <botan/internal/argon2_ssse3.h>
 #include <tmmintrin.h>
 
 namespace Botan {
@@ -228,57 +228,32 @@ BOTAN_FORCE_INLINE void blamka_R(
 
 }
 
-void Argon2::blamka_ssse3(uint64_t N[128], uint64_t T[128])
+void blamka_ssse3(uint64_t T[128])
    {
    for(size_t i = 0; i != 8; ++i)
       {
       SIMD_2x64 Tv[8];
-      for(size_t j = 0; j != 4; ++j)
-         {
-         Tv[2*j] = SIMD_2x64::load_le(&N[16*i+4*j]);
-         Tv[2*j+1] = SIMD_2x64::load_le(&N[16*i+4*j+2]);
-         }
+      for(size_t j = 0; j != 8; ++j)
+         Tv[j] = SIMD_2x64::load_le(&T[2*(8*i+j)]);
 
       blamka_R(Tv[0], Tv[1], Tv[2], Tv[3],
                Tv[4], Tv[5], Tv[6], Tv[7]);
 
-      for(size_t j = 0; j != 4; ++j)
-         {
-         Tv[2*j].store_le(&T[16*i + 4*j]);
-         Tv[2*j+1].store_le(&T[16*i + 4*j + 2]);
-         }
+      for(size_t j = 0; j != 8; ++j)
+         Tv[j].store_le(&T[2*(8*i+j)]);
       }
 
    for(size_t i = 0; i != 8; ++i)
       {
       SIMD_2x64 Tv[8];
-      for(size_t j = 0; j != 4; ++j)
-         {
-         Tv[2*j] = SIMD_2x64::load_le(&T[2*i + 32*j]);
-         Tv[2*j+1] = SIMD_2x64::load_le(&T[2*i + 32*j + 16]);
-         }
+      for(size_t j = 0; j != 8; ++j)
+         Tv[j] = SIMD_2x64::load_le(&T[2*(i+8*j)]);
 
       blamka_R(Tv[0], Tv[1], Tv[2], Tv[3],
                Tv[4], Tv[5], Tv[6], Tv[7]);
 
-      for(size_t j = 0; j != 4; ++j)
-         {
-         Tv[2*j].store_le(&T[2*i + 32*j]);
-         Tv[2*j+1].store_le(&T[2*i + 32*j + 16]);
-         }
-      }
-
-   for(size_t i = 0; i != 128 / 4; ++i)
-      {
-      SIMD_2x64 n0 = SIMD_2x64::load_le(&N[4*i]);
-      SIMD_2x64 n1 = SIMD_2x64::load_le(&N[4*i+2]);
-      SIMD_2x64 t0 = SIMD_2x64::load_le(&T[4*i]);
-      SIMD_2x64 t1 = SIMD_2x64::load_le(&T[4*i+2]);
-
-      n0 ^= t0;
-      n1 ^= t1;
-      n0.store_le(&N[4*i]);
-      n1.store_le(&N[4*i+2]);
+      for(size_t j = 0; j != 8; ++j)
+         Tv[j].store_le(&T[2*(i+8*j)]);
       }
    }
 
diff --git a/src/lib/pbkdf/argon2/argon2_ssse3/argon2_ssse3.h b/src/lib/pbkdf/argon2/argon2_ssse3/argon2_ssse3.h
new file mode 100644
index 000000000..adf64c64e
--- /dev/null
+++ b/src/lib/pbkdf/argon2/argon2_ssse3/argon2_ssse3.h
@@ -0,0 +1,18 @@
+/**
+* (C) 2022 Jack Lloyd
+*
+* Botan is released under the Simplified BSD License (see license.txt)
+*/
+
+#ifndef BOTAN_ARGON2_SSSE3_H_
+#define BOTAN_ARGON2_SSSE3_H_
+
+#include <botan/types.h>
+
+namespace Botan {
+
+void blamka_ssse3(uint64_t T[128]);
+
+}
+
+#endif
diff --git a/src/lib/tls/tls13/tls_transcript_hash_13.cpp b/src/lib/tls/tls13/tls_transcript_hash_13.cpp
index edf9e4f33..980666851 100644
--- a/src/lib/tls/tls13/tls_transcript_hash_13.cpp
+++ b/src/lib/tls/tls13/tls_transcript_hash_13.cpp
@@ -78,8 +78,10 @@ namespace {
 //
 // Finds the truncation offset in a serialization of Client Hello as defined in
 // RFC 8446 4.2.11.2 used for the calculation of PSK binder MACs.
-size_t find_client_hello_truncation_mark(std::span<const uint8_t> client_hello)
+size_t find_client_hello_truncation_mark(std::vector<uint8_t> client_hello)
    {
+   // TODO: C++20: it would be great if TLS_Data_Reader could optionally deal
+   //       with std::span. This would have saved one allocation of std::vector.
    TLS_Data_Reader reader("Client Hello Truncation", client_hello);
 
    // handshake message type
@@ -157,7 +159,7 @@ std::vector<uint8_t> read_hash_state(std::unique_ptr<HashFunction>& hash)
 void Transcript_Hash_State::update(std::span<const uint8_t> serialized_message_s)
    {
    auto serialized_message = serialized_message_s.data();
-   auto serialized_message_length = serialized_message_s.size();
+   auto serialized_message_length = serialized_message_s.end() - serialized_message_s.begin();
    if(m_hash != nullptr)
       {
       auto truncation_mark = serialized_message_length;
@@ -167,7 +169,8 @@ void Transcript_Hash_State::update(std::span<const uint8_t> serialized_message_s
       if(serialized_message_length > 0 && *serialized_message == CLIENT_HELLO)
          {
          truncation_mark =
-            find_client_hello_truncation_mark(serialized_message_s);
+            find_client_hello_truncation_mark({serialized_message,
+                                               serialized_message + serialized_message_length});
          }
 
       if(truncation_mark < serialized_message_length)
diff --git a/src/lib/tls/tls_reader.h b/src/lib/tls/tls_reader.h
index 6f0fb70fe..6bd5b7e6b 100644
--- a/src/lib/tls/tls_reader.h
+++ b/src/lib/tls/tls_reader.h
@@ -13,7 +13,6 @@
 #include <botan/internal/loadstor.h>
 #include <string>
 #include <vector>
-#include <span>
 
 namespace Botan {
 
@@ -25,7 +24,7 @@ namespace TLS {
 class TLS_Data_Reader final
    {
    public:
-      TLS_Data_Reader(const char* type, std::span<const uint8_t> buf_in) :
+      TLS_Data_Reader(const char* type, const std::vector<uint8_t>& buf_in) :
          m_typename(type), m_buf(buf_in), m_offset(0) {}
 
       void assert_done() const
@@ -202,7 +201,7 @@ class TLS_Data_Reader final
          }
 
       const char* m_typename;
-      std::span<const uint8_t> m_buf;
+      const std::vector<uint8_t>& m_buf;
       size_t m_offset;
    };
 
diff --git a/src/lib/utils/thread_utils/info.txt b/src/lib/utils/thread_utils/info.txt
index fd583a90f..7aeb364fb 100644
--- a/src/lib/utils/thread_utils/info.txt
+++ b/src/lib/utils/thread_utils/info.txt
@@ -9,7 +9,6 @@ name -> "Thread Utilities"
 <header:internal>
 rwlock.h
 barrier.h
-semaphore.h
 thread_pool.h
 </header:internal>
 
diff --git a/src/lib/utils/thread_utils/semaphore.cpp b/src/lib/utils/thread_utils/semaphore.cpp
deleted file mode 100644
index 0858a013f..000000000
--- a/src/lib/utils/thread_utils/semaphore.cpp
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-* Semaphore
-* (C) 2013 Joel Low
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#include <botan/internal/semaphore.h>
-
-// Based on code by Pierre Gaston (http://p9as.blogspot.com/2012/06/c11-semaphores.html)
-
-namespace Botan {
-
-void Semaphore::release(size_t n)
-   {
-   for(size_t i = 0; i != n; ++i)
-      {
-      std::lock_guard<std::mutex> lock(m_mutex);
-
-      if(m_value++ < 0)
-         {
-         ++m_wakeups;
-         m_cond.notify_one();
-         }
-      }
-   }
-
-void Semaphore::acquire()
-   {
-   std::unique_lock<std::mutex> lock(m_mutex);
-   if(m_value-- <= 0)
-       {
-       m_cond.wait(lock, [this] { return m_wakeups > 0; });
-       --m_wakeups;
-       }
-   }
-
-}
diff --git a/src/lib/utils/thread_utils/semaphore.h b/src/lib/utils/thread_utils/semaphore.h
deleted file mode 100644
index 538d9ecb5..000000000
--- a/src/lib/utils/thread_utils/semaphore.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
-* Semaphore
-* (C) 2013 Joel Low
-*
-* Botan is released under the Simplified BSD License (see license.txt)
-*/
-
-#ifndef BOTAN_SEMAPHORE_H_
-#define BOTAN_SEMAPHORE_H_
-
-#include <condition_variable>
-#include <mutex>
-
-namespace Botan {
-
-class Semaphore final
-   {
-   public:
-      explicit Semaphore(int value = 0) : m_value(value), m_wakeups(0) {}
-
-      void acquire();
-
-      void release(size_t n = 1);
-
-   private:
-      int m_value;
-      int m_wakeups;
-      std::mutex m_mutex;
-      std::condition_variable m_cond;
-   };
-
-}
-
-#endif


Test patch:
diff --git a/src/tests/data/argon2.vec b/src/tests/data/argon2.vec
index 12d407a88..e4db43da3 100644
--- a/src/tests/data/argon2.vec
+++ b/src/tests/data/argon2.vec
@@ -1,4 +1,3 @@
-#test cpuid avx2 ssse3
 
 # First three are the official test vectors
 
diff --git a/src/tests/runner/test_runner.cpp b/src/tests/runner/test_runner.cpp
index c8487c2db..cb22c0b0f 100644
--- a/src/tests/runner/test_runner.cpp
+++ b/src/tests/runner/test_runner.cpp
@@ -271,8 +271,6 @@ bool needs_serialization(const std::string& test_name)
       return true;
    if(test_name == "block" || test_name == "hash" || test_name == "mac" || test_name == "stream" || test_name == "aead")
       return true;
-   if(test_name == "argon2")
-      return true;
    if(test_name == "ecc_unit")
       return false;
    return false;