Repository: randombit/botan
Pull request #2817 (2021-10-12 12:38:17)

CI: Let AppVeyor use boost 1.77
Getting additional data points to investigate #2816.


Patch:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index dccff6cbd..198ed5722 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -59,9 +59,6 @@ jobs:
           - target: cross-win64
             compiler: gcc
             host_os: ubuntu-20.04
-          - target: amalgamation
-            compiler: gcc
-            host_os: ubuntu-20.04
           - target: baremetal
             compiler: gcc
             host_os: ubuntu-20.04
diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml
deleted file mode 100644
index 0b827868e..000000000
--- a/.github/workflows/cifuzz.yml
+++ /dev/null
@@ -1,24 +0,0 @@
-name: CIFuzz
-on: [pull_request]
-jobs:
-  Fuzzing:
-    runs-on: ubuntu-latest
-    steps:
-    - name: Build Fuzzers
-      id: build
-      uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
-      with:
-        oss-fuzz-project-name: 'botan'
-        dry-run: false
-    - name: Run Fuzzers
-      uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
-      with:
-        oss-fuzz-project-name: 'botan'
-        fuzz-seconds: 600
-        dry-run: false
-    - name: Upload Crash
-      uses: actions/upload-artifact@v1
-      if: failure() && steps.build.outcome == 'success'
-      with:
-        name: artifacts
-        path: ./out/artifacts
diff --git a/.travis.yml b/.travis.yml
new file mode 120000
index 000000000..0a16c6e8f
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,1 @@
+src/scripts/ci/travis.yml
\ No newline at end of file
diff --git a/doc/cli.rst b/doc/cli.rst
index 8eafece33..37698cef7 100644
--- a/doc/cli.rst
+++ b/doc/cli.rst
@@ -207,7 +207,7 @@ TLS Server/Client
 -----------------------
 
 The ``--policy=`` argument of the TLS commands specifies the TLS policy to use.
-The policy can be any of the strings "default", "suiteb_128", "suiteb_192",
+The policy can be any of the the strings "default", "suiteb_128", "suiteb_192",
 "bsi", "strict", or "all" to denote built-in policies, or it can name a file
 from which a policy description will be read.
 
diff --git a/doc/old_news.rst b/doc/old_news.rst
index a5afd369b..161bf487b 100644
--- a/doc/old_news.rst
+++ b/doc/old_news.rst
@@ -1189,7 +1189,7 @@ Version 1.11.16, 2015-03-29
   Unfortunately the semantics of the exchange have changed with ALPN. Using
   NPN, the server offered a list of protocols it advertised, and then the
   client chose its favorite. With ALPN, the client offers a list of protocols
-  and the server chooses. The signatures of both the TLS::Client and
+  and the server chooses. The the signatures of both the TLS::Client and
   TLS::Server constructors have changed to support this new flow.
 
 * Optimized ECDSA signature verification thanks to an observation by
@@ -2402,7 +2402,7 @@ Version 1.9.15, 2011-03-21
   causing a illegal instruction crash.
 
 * Improve detection and autoconfiguration for ARM processors. Thanks
-  go out to the `Tahoe-LAFS Software Foundation
+  go out to the the `Tahoe-LAFS Software Foundation
   <http://tahoe-lafs.org>`_, who donated a Sheevaplug that I'll be
   using to figure out how to make the cryptographic primitives
   Tahoe-LAFS relies on faster, particularly targeting the ARMv5TE.
diff --git a/news.rst b/news.rst
index 37fd92c86..1b0b89548 100644
--- a/news.rst
+++ b/news.rst
@@ -136,29 +136,6 @@ Version 3.0.0, Not Yet Released
 
 * Generate a ``compile_commands.json`` for use with Clang tooling.
 
-Version 2.18.2, 2021-10-25
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-* Avoid using short exponents when encrypting in ElGamal, as some PGP
-  implementations generate keys with parameters that are weak when
-  short exponents are used (GH #2794)
-
-* Fix a low risk OAEP decryption side channel (GH #2797)
-
-* Work around a miscompilation of SHA-3 caused by a bug in Clang 12
-  and XCode 13. (GH #2826)
-
-* Remove support in OpenSSL provider for algorithms which are
-  disabled by default in OpenSSL 3.0 (GH #2823, #2814)
-
-* Add CI based on GitHub actions to replace Travis CI (GH #2632)
-
-* Fix the online OCSP test, as the certificate involved had expired.
-  (GH #2799)
-
-* Fix some test failures induced by the expiration of the trust root
-  "DST Root CA X3" (GH #2820)
-
 Version 2.18.1, 2021-05-09
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
diff --git a/readme.rst b/readme.rst
index aae215094..5df9e789f 100644
--- a/readme.rst
+++ b/readme.rst
@@ -27,9 +27,9 @@ If you think you have found a security issue, see the `security page
 <https://botan.randombit.net/security.html>`_ for contact information.
 
 The latest release is
-`2.18.2 <https://botan.randombit.net/releases/Botan-2.18.2.tar.xz>`_
-`(sig) <https://botan.randombit.net/releases/Botan-2.18.2.tar.xz.asc>`_,
-released on 2021-10-25.
+`2.18.1 <https://botan.randombit.net/releases/Botan-2.18.1.tar.xz>`_
+`(sig) <https://botan.randombit.net/releases/Botan-2.18.1.tar.xz.asc>`_,
+released on 2021-05-09.
 All releases are signed with a `PGP key <https://botan.randombit.net/pgpkey.txt>`_.
 See the `release notes <https://botan.randombit.net/news.html>`_ for
 what is new. Botan is also available through most
diff --git a/src/build-data/cc/clang.txt b/src/build-data/cc/clang.txt
index e46534303..896109590 100644
--- a/src/build-data/cc/clang.txt
+++ b/src/build-data/cc/clang.txt
@@ -37,8 +37,6 @@ macos         -> "$(CXX) -dynamiclib -fPIC -install_name $(INSTALLED_LIB_DIR)/{s
 
 # The default works for GNU ld and several other Unix linkers
 default       -> "$(CXX) -shared -fPIC -Wl,-soname,{soname_abi}"
-
-mingw         -> "$(CXX) -shared -Wl,--out-implib,{shared_lib_name}.a"
 </so_link_commands>
 
 <binary_link_commands>
diff --git a/src/build-data/cc/gcc.txt b/src/build-data/cc/gcc.txt
index eb872e75e..e4a6bda8e 100644
--- a/src/build-data/cc/gcc.txt
+++ b/src/build-data/cc/gcc.txt
@@ -45,8 +45,6 @@ solaris -> "$(CXX) -shared -fPIC -Wl,-h,{soname_abi}"
 # AIX and OpenBSD don't use sonames at all
 aix     -> "$(CXX) -shared -fPIC"
 openbsd -> "$(CXX) -shared -fPIC"
-
-mingw   -> "$(CXX) -shared -Wl,--out-implib,{shared_lib_name}.a"
 </so_link_commands>
 
 <binary_link_commands>
diff --git a/src/build-data/os/mingw.txt b/src/build-data/os/mingw.txt
index 836da6e9d..b2cc2f0b8 100644
--- a/src/build-data/os/mingw.txt
+++ b/src/build-data/os/mingw.txt
@@ -8,9 +8,6 @@ header_dir include
 lib_dir lib
 doc_dir share/doc
 
-soname_pattern_base "{lib_prefix}{libname}.dll"
-shared_lib_symlinks no
-
 # see https://sourceforge.net/p/mingw-w64/bugs/755/
 use_stack_protector no
 
diff --git a/src/lib/ffi/ffi.h b/src/lib/ffi/ffi.h
index a49437440..25a30e057 100644
--- a/src/lib/ffi/ffi.h
+++ b/src/lib/ffi/ffi.h
@@ -168,7 +168,7 @@ BOTAN_PUBLIC_API(2,2) int botan_scrub_mem(void* mem, size_t bytes);
 * @param len length of x in bytes
 * @param out an array of at least x*2 bytes
 * @param flags flags out be upper or lower case?
-* @return 0 on success, a negative value on failure
+* @return 0 on success, 1 on failure
 */
 BOTAN_PUBLIC_API(2,0) int botan_hex_encode(const uint8_t* x, size_t len, char* out, uint32_t flags);
 
@@ -177,8 +177,7 @@ BOTAN_PUBLIC_API(2,0) int botan_hex_encode(const uint8_t* x, size_t len, char* o
 * @param hex_str a string of hex chars (whitespace is ignored)
 * @param in_len the length of hex_str
 * @param out the output buffer should be at least strlen(hex_str)/2 bytes
-* @param out_len the size of the output buffer on input, set to the number of bytes written
-* @return 0 on success, a negative value on failure
+* @param out_len the size of out
 */
 BOTAN_PUBLIC_API(2,3) int botan_hex_decode(const char* hex_str, size_t in_len, uint8_t* out, size_t* out_len);
 
@@ -239,7 +238,7 @@ BOTAN_PUBLIC_API(2,0) int botan_rng_get(botan_rng_t rng, uint8_t* out, size_t ou
 * Uses the System_RNG as a seed generator.
 *
 * @param rng rng object
-* @param bits number of bits to reseed with
+* @param bits number of bits to to reseed with
 * @return 0 on success, a negative value on failure
 */
 BOTAN_PUBLIC_API(2,0) int botan_rng_reseed(botan_rng_t rng, size_t bits);
@@ -249,7 +248,7 @@ BOTAN_PUBLIC_API(2,0) int botan_rng_reseed(botan_rng_t rng, size_t bits);
 *
 * @param rng rng object
 * @param source_rng the rng that will be read from
-* @param bits number of bits to reseed with
+* @param bits number of bits to to reseed with
 * @return 0 on success, a negative value on failure
 */
 BOTAN_PUBLIC_API(2,8) int botan_rng_reseed_from_rng(botan_rng_t rng,
@@ -1146,7 +1145,7 @@ BOTAN_PUBLIC_API(2,0) int botan_pubkey_fingerprint(botan_pubkey_t key, const cha
 BOTAN_PUBLIC_API(2,0) int botan_pubkey_destroy(botan_pubkey_t key);
 
 /*
-* Get arbitrary named fields from public or private keys
+* Get arbitrary named fields from public or privat keys
 */
 BOTAN_PUBLIC_API(2,0) int botan_pubkey_get_field(botan_mp_t output,
                                      botan_pubkey_t key,
diff --git a/src/lib/hash/sha3/sha3.cpp b/src/lib/hash/sha3/sha3.cpp
index 6df417016..5504a683d 100644
--- a/src/lib/hash/sha3/sha3.cpp
+++ b/src/lib/hash/sha3/sha3.cpp
@@ -11,40 +11,17 @@
 #include <botan/exceptn.h>
 #include <botan/internal/cpuid.h>
 
-#include <tuple>
-
 namespace Botan {
 
 namespace {
 
-// This is a workaround for a suspected bug in clang 12 (and XCode 13)
-// that caused a miscompile of the SHA3 implementation for optimization
-// level -O2 and higher.
-//
-// For details, see: https://github.com/randombit/botan/issues/2802
-#if    defined(__clang__) && \
-    (( defined(__apple_build_version__) && __clang_major__ == 13) || \
-     (!defined(__apple_build_version__) && __clang_major__ == 12))
-#define BOTAN_WORKAROUND_MAYBE_INLINE __attribute__((noinline))
-#else
-#define BOTAN_WORKAROUND_MAYBE_INLINE inline
-#endif
-
-BOTAN_WORKAROUND_MAYBE_INLINE decltype(auto) xor_CNs(const uint64_t A[25])
-   {
-   return std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>(
-      A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20],
-      A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21],
-      A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22],
-      A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23],
-      A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]);
-   }
-
-#undef BOTAN_WORKAROUND_MAYBE_INLINE
-
 inline void SHA3_round(uint64_t T[25], const uint64_t A[25], uint64_t RC)
    {
-   const auto [C0,C1,C2,C3,C4] = xor_CNs(A);
+   const uint64_t C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20];
+   const uint64_t C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21];
+   const uint64_t C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22];
+   const uint64_t C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23];
+   const uint64_t C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24];
 
    const uint64_t D0 = rotl<1>(C0) ^ C3;
    const uint64_t D1 = rotl<1>(C1) ^ C4;
diff --git a/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp b/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp
index 3483fd872..9eac416ab 100644
--- a/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp
+++ b/src/lib/hash/sha3/sha3_bmi2/sha3_bmi2.cpp
@@ -8,40 +8,17 @@
 #include <botan/internal/sha3.h>
 #include <botan/internal/rotate.h>
 
-#include <tuple>
-
 namespace Botan {
 
 namespace {
 
-// This is a workaround for a suspected bug in clang 12 (and XCode 13)
-// that caused a miscompile of the SHA3 implementation for optimization
-// level -O2 and higher.
-//
-// For details, see: https://github.com/randombit/botan/issues/2802
-#if    defined(__clang__) && \
-    (( defined(__apple_build_version__) && __clang_major__ == 13) || \
-     (!defined(__apple_build_version__) && __clang_major__ == 12))
-#define BOTAN_WORKAROUND_MAYBE_INLINE __attribute__((noinline))
-#else
-#define BOTAN_WORKAROUND_MAYBE_INLINE inline
-#endif
-
-BOTAN_WORKAROUND_MAYBE_INLINE decltype(auto) xor_CNs_BMI2(const uint64_t A[25])
-   {
-   return std::tuple<uint64_t, uint64_t, uint64_t, uint64_t, uint64_t>(
-      A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20],
-      A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21],
-      A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22],
-      A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23],
-      A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24]);
-   }
-
-#undef BOTAN_WORKAROUND_MAYBE_INLINE
-
 inline void SHA3_BMI2_round(uint64_t T[25], const uint64_t A[25], uint64_t RC)
    {
-   const auto [C0,C1,C2,C3,C4] = xor_CNs_BMI2(A);
+   const uint64_t C0 = A[0] ^ A[5] ^ A[10] ^ A[15] ^ A[20];
+   const uint64_t C1 = A[1] ^ A[6] ^ A[11] ^ A[16] ^ A[21];
+   const uint64_t C2 = A[2] ^ A[7] ^ A[12] ^ A[17] ^ A[22];
+   const uint64_t C3 = A[3] ^ A[8] ^ A[13] ^ A[18] ^ A[23];
+   const uint64_t C4 = A[4] ^ A[9] ^ A[14] ^ A[19] ^ A[24];
 
    const uint64_t D0 = rotl<1>(C0) ^ C3;
    const uint64_t D1 = rotl<1>(C1) ^ C4;
diff --git a/src/lib/prov/openssl/openssl_block.cpp b/src/lib/prov/openssl/openssl_block.cpp
index 7b5022b7b..b9972462c 100644
--- a/src/lib/prov/openssl/openssl_block.cpp
+++ b/src/lib/prov/openssl/openssl_block.cpp
@@ -230,10 +230,27 @@ make_openssl_block_cipher(const std::string& name)
 #endif
 
 #if defined(BOTAN_HAS_DES) && !defined(OPENSSL_NO_DES)
+   if(name == "DES")
+      return MAKE_OPENSSL_BLOCK(EVP_des_ecb);
    if(name == "TripleDES")
       return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_des_ede3_ecb, 16, 24, 8);
 #endif
 
+#if defined(BOTAN_HAS_BLOWFISH) && !defined(OPENSSL_NO_BF)
+   if(name == "Blowfish")
+      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_bf_ecb, 1, 56, 1);
+#endif
+
+#if defined(BOTAN_HAS_CAST_128) && !defined(OPENSSL_NO_CAST)
+   if(name == "CAST-128")
+      return MAKE_OPENSSL_BLOCK_KEYLEN(EVP_cast5_ecb, 1, 16, 1);
+#endif
+
+#if defined(BOTAN_HAS_SEED) && !defined(OPENSSL_NO_SEED)
+   if(name == "SEED")
+      return MAKE_OPENSSL_BLOCK(EVP_seed_ecb);
+#endif
+
    return nullptr;
    }
 
diff --git a/src/lib/prov/openssl/openssl_hash.cpp b/src/lib/prov/openssl/openssl_hash.cpp
index 32ba318eb..7b542220f 100644
--- a/src/lib/prov/openssl/openssl_hash.cpp
+++ b/src/lib/prov/openssl/openssl_hash.cpp
@@ -125,11 +125,26 @@ make_openssl_hash(const std::string& name)
       return MAKE_OPENSSL_HASH(EVP_sha1);
 #endif
 
+#if defined(BOTAN_HAS_RIPEMD_160) && !defined(OPENSSL_NO_RIPEMD)
+   if(name == "RIPEMD-160")
+      return MAKE_OPENSSL_HASH(EVP_ripemd160);
+#endif
+
 #if defined(BOTAN_HAS_MD5) && !defined(OPENSSL_NO_MD5)
    if(name == "MD5")
       return MAKE_OPENSSL_HASH(EVP_md5);
    #endif
 
+#if defined(BOTAN_HAS_MD4) && !defined(OPENSSL_NO_MD4)
+   if(name == "MD4")
+      return MAKE_OPENSSL_HASH(EVP_md4);
+#endif
+
+#if defined(BOTAN_HAS_WHIRLPOOL) && !defined(OPENSSL_NO_WHIRLPOOL)
+   if(name == "Whirlpool")
+      return MAKE_OPENSSL_HASH(EVP_whirlpool);
+#endif
+
    return nullptr;
    }
 
diff --git a/src/lib/pubkey/xmss/xmss_common_ops.h b/src/lib/pubkey/xmss/xmss_common_ops.h
index 9a3223df4..d04e65242 100644
--- a/src/lib/pubkey/xmss/xmss_common_ops.h
+++ b/src/lib/pubkey/xmss/xmss_common_ops.h
@@ -39,7 +39,7 @@ class XMSS_Common_Ops
         * @param[in] right Right half of the hash function input.
         * @param[in] adrs Adress of the hash function call.
         * @param[in] seed The seed for G.
-        * @param[in] hash Instance of XMSS_Hash, that may only by the thread
+        * @param[in] hash Instance of XMSS_Hash, that may only by the thead
         *            executing generate_public_key.
         * @param[in] params
         **/
@@ -66,7 +66,7 @@ class XMSS_Common_Ops
        * @param[in] adrs Address encoding the address of the L-Tree
        * @param[in] seed The seed generated during the public key generation.
        * @param[in] hash Instance of XMSS_Hash, that may only be used by the
-       *            thread executing create_l_tree.
+       *            thead executing create_l_tree.
        * @param[in] params
       **/
       static void create_l_tree(secure_vector<uint8_t>& result,
diff --git a/src/lib/pubkey/xmss/xmss_wots.h b/src/lib/pubkey/xmss/xmss_wots.h
index dc1c2ba78..060d54711 100644
--- a/src/lib/pubkey/xmss/xmss_wots.h
+++ b/src/lib/pubkey/xmss/xmss_wots.h
@@ -391,7 +391,7 @@ class XMSS_WOTS_PublicKey : virtual public Public_Key
        * @param steps A number of steps.
        * @param adrs An OTS Hash Address.
        * @param public_seed A public seed.
-       * @param hash Instance of XMSS_Hash, that may only by the thread
+       * @param hash Instance of XMSS_Hash, that may only by the thead
        *        executing chain.
        **/
       void chain(secure_vector<uint8_t>& x,
@@ -551,7 +551,7 @@ class XMSS_WOTS_PrivateKey final : public virtual XMSS_WOTS_PublicKey,
        *
        * @param i Index of the key to retrieve.
        * @param hash Instance of XMSS_Hash, that may only be used by the
-       *        thread executing at.
+       *        thead executing at.
        *
        * @return WOTS secret key.
        **/
@@ -580,7 +580,7 @@ class XMSS_WOTS_PrivateKey final : public virtual XMSS_WOTS_PublicKey,
        *
        * @param adrs The address of the key to retrieve.
        * @param hash Instance of XMSS_Hash, that may only be used by the
-       *        thread executing at.
+       *        thead executing at.
        *
        * @return WOTS secret key.
        **/
@@ -620,7 +620,7 @@ class XMSS_WOTS_PrivateKey final : public virtual XMSS_WOTS_PublicKey,
        *        public key generation.
        * @param adrs Hash function address encoding the address of
        *        the WOTS+ key pair within a greater structure.
-       * @param hash Instance of XMSS_Hash, that may only by the thread
+       * @param hash Instance of XMSS_Hash, that may only by the thead
        *        executing generate_public_key.
        **/
       void generate_public_key(XMSS_WOTS_PublicKey& pub_key,
@@ -674,7 +674,7 @@ class XMSS_WOTS_PrivateKey final : public virtual XMSS_WOTS_PublicKey,
        * @param adrs An OTS hash address identifying the WOTS+ key pair
        *        used for signing.
        * @param hash Instance of XMSS_Hash, that may only be used by the
-       *        thread executing sign.
+       *        thead executing sign.
        *
        * @return signature for msg.
        **/
@@ -736,7 +736,7 @@ class XMSS_WOTS_PrivateKey final : public virtual XMSS_WOTS_PublicKey,
        *
        * @param private_seed Uniformly random n-byte value.
        * @param[in] hash Instance of XMSS_Hash, that may only be used by the
-       *            thread executing generate.
+       *            thead executing generate.
        *
        * @returns a vector of length key_size() of vectors of n bytes length
        *          containing uniformly random data.
diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp
index 74894f04f..e278a6d07 100644
--- a/src/lib/utils/os_utils.cpp
+++ b/src/lib/utils/os_utils.cpp
@@ -265,34 +265,30 @@ uint64_t OS::get_cpu_cycle_counter()
    return rtc;
    }
 
-size_t OS::get_cpu_available()
+size_t OS::get_cpu_total()
    {
-#if defined(BOTAN_TARGET_OS_HAS_POSIX1)
-
-#if defined(_SC_NPROCESSORS_ONLN)
-   const long cpu_online = ::sysconf(_SC_NPROCESSORS_ONLN);
-   if(cpu_online > 0)
-      return static_cast<size_t>(cpu_online);
-#endif
-
-#if defined(_SC_NPROCESSORS_CONF)
-   const long cpu_conf = ::sysconf(_SC_NPROCESSORS_CONF);
-   if(cpu_conf > 0)
-      return static_cast<size_t>(cpu_conf);
-#endif
-
+#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_CONF)
+   const long res = ::sysconf(_SC_NPROCESSORS_CONF);
+   if(res > 0)
+      return static_cast<size_t>(res);
 #endif
 
 #if defined(BOTAN_TARGET_OS_HAS_THREADS)
-   // hardware_concurrency is allowed to return 0 if the value is not
-   // well defined or not computable.
-   const size_t hw_concur = std::thread::hardware_concurrency();
+   return static_cast<size_t>(std::thread::hardware_concurrency());
+#else
+   return 1;
+#endif
+   }
 
-   if(hw_concur > 0)
-      return hw_concur;
+size_t OS::get_cpu_available()
+   {
+#if defined(BOTAN_TARGET_OS_HAS_POSIX1) && defined(_SC_NPROCESSORS_ONLN)
+   const long res = ::sysconf(_SC_NPROCESSORS_ONLN);
+   if(res > 0)
+      return static_cast<size_t>(res);
 #endif
 
-   return 1;
+   return OS::get_cpu_total();
    }
 
 uint64_t OS::get_high_resolution_clock()
diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h
index 6fe3efe77..9cefb9b41 100644
--- a/src/lib/utils/os_utils.h
+++ b/src/lib/utils/os_utils.h
@@ -50,6 +50,7 @@ bool running_in_privileged_state();
 */
 uint64_t BOTAN_TEST_API get_cpu_cycle_counter();
 
+size_t BOTAN_TEST_API get_cpu_total();
 size_t BOTAN_TEST_API get_cpu_available();
 
 /**
diff --git a/src/python/botan2.py b/src/python/botan2.py
index 3a868db46..003c98f21 100755
--- a/src/python/botan2.py
+++ b/src/python/botan2.py
@@ -63,8 +63,6 @@ def _load_botan_dll(expected_version):
     if platform in ['win32', 'cygwin', 'msys']:
         possible_dll_names.append('botan-3.dll')
         possible_dll_names.append('botan.dll')
-        possible_dll_names.append('libbotan-3.dll')
-        possible_dll_names.append('libbotan-2.dll')
     elif platform in ['darwin', 'macos']:
         possible_dll_names.append('libbotan-3.dylib')
         possible_dll_names.append('libbotan-2.dylib')
diff --git a/src/scripts/ci/appveyor.yml b/src/scripts/ci/appveyor.yml
index 08be4e28f..70bd5f362 100644
--- a/src/scripts/ci/appveyor.yml
+++ b/src/scripts/ci/appveyor.yml
@@ -25,18 +25,26 @@ environment:
       PLATFORM: x86_amd64
       TARGET: static
       APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
-      BOOST_ROOT: "C:\\Libraries\\boost_1_73_0"
-      BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_73_0\\lib64-msvc-14.2"
-      BOOST_SYSTEM_LIBRARY: "libboost_system-vc142-mt-x64-1_73"
+      BOOST_ROOT: "C:\\Libraries\\boost_1_77_0"
+      BOOST_LIBRARYDIR: "C:\\Libraries\\boost_1_77_0\\lib64-msvc-14.2"
+      BOOST_SYSTEM_LIBRARY: "libboost_system-vc142-mt-x64-1_77"
       MAKE_TOOL: jom
       TARGET_CC: msvc
       EXTRA_FLAGS: "--extra-cxxflags=/DUNICODE --extra-cxxflags=/D_UNICODE"
 
+    # MSVC 2019 x86-64 preview
+    - CC: VC2019p
+      PLATFORM: x86_amd64
+      TARGET: shared
+      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 Preview
+      MAKE_TOOL: jom
+      TARGET_CC: msvc
+
     # MinGW GCC
     - CC: MinGW
       PLATFORM: x86_amd64
       TARGET: static
-      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+      APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
       MAKE_TOOL: mingw32-make
       TARGET_CC: gcc
 
diff --git a/src/scripts/ci/setup_appveyor.bat b/src/scripts/ci/setup_appveyor.bat
index d9635a2f0..918af9492 100644
--- a/src/scripts/ci/setup_appveyor.bat
+++ b/src/scripts/ci/setup_appveyor.bat
@@ -5,6 +5,7 @@ rem Botan is released under the Simplified BSD License (see license.txt)
 echo Current build setup CC="%CC%" PLATFORM="%PLATFORM%" TARGET="%TARGET%"
 
 if %CC% == VC2019 call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM%
+if %CC% == VC2019p call "%ProgramFiles(x86)%\Microsoft Visual Studio\2019\Preview\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM%
 if %CC% == MinGW set PATH=%PATH%;C:\msys64\mingw64\bin
 
 rem check compiler version
diff --git a/src/scripts/ci/setup_travis.sh b/src/scripts/ci/setup_travis.sh
new file mode 100755
index 000000000..d6d206c3f
--- /dev/null
+++ b/src/scripts/ci/setup_travis.sh
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# Travis CI setup script for Botan build
+#
+# (C) 2015,2017 Simon Warta
+# (C) 2016,2017,2018 Jack Lloyd
+#
+# Botan is released under the Simplified BSD License (see license.txt)
+
+command -v shellcheck > /dev/null && shellcheck "$0" # Run shellcheck on this if available
+
+set -ex
+
+if [ "$TRAVIS_OS_NAME" = "linux" ]; then
+
+    if [ "$TARGET" = "valgrind" ]; then
+        sudo apt-get -qq update
+        sudo apt-get install valgrind
+
+    elif [ "$TARGET" = "cross-i386" ]; then
+        sudo apt-get -qq update
+        sudo apt-get install g++-multilib linux-libc-dev libc6-dev-i386
+
+    elif [ "$TARGET" = "cross-win64" ]; then
+        sudo apt-get -qq update
+        sudo apt-get install wine-development g++-mingw-w64-x86-64
+
+    elif [ "$TARGET" = "cross-arm32" ]; then
+        sudo dpkg --add-architecture armhf
+        sudo apt-get -qq update
+        sudo apt-get install g++-arm-linux-gnueabihf
+        sudo apt-get install -o APT::Immediate-Configure=0 libc6:armhf libstdc++6:armhf
+
+    elif [ "$TARGET" = "cross-android-arm32" ] || [ "$TARGET" = "cross-android-arm64" ]; then
+        wget -nv https://dl.google.com/android/repository/"$ANDROID_NDK"-linux-x86_64.zip
+        unzip -qq "$ANDROID_NDK"-linux-x86_64.zip
+
+    elif [ "$TARGET" = "baremetal" ]; then
+        sudo apt-get -qq update
+        sudo apt-get install gcc-arm-none-eabi libstdc++-arm-none-eabi-newlib
+
+        echo 'extern "C" void __sync_synchronize() {}' >> src/tests/main.cpp
+        echo 'extern "C" void __sync_synchronize() {}' >> src/cli/main.cpp
+
+    elif [ "$TARGET" = "lint" ]; then
+        sudo apt-get -qq update
+        sudo apt-get install pylint
+
+    elif [ "$TARGET" = "docs" ]; then
+        sudo apt-get -qq update
+        sudo apt-get install doxygen python-docutils python3-sphinx
+    fi
+
+elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
+    HOMEBREW_NO_AUTO_UPDATE=1 brew install ccache
+fi
diff --git a/src/scripts/ci/travis.yml b/src/scripts/ci/travis.yml
new file mode 100644
index 000000000..8ecc8c544
--- /dev/null
+++ b/src/scripts/ci/travis.yml
@@ -0,0 +1,65 @@
+
+# (C) 2015,2016,2017,2019,2020,2021 Jack Lloyd
+# (C) 2015,2016 Simon Warta
+# Botan is released under the Simplified BSD License (see license.txt)
+
+language: cpp
+os: linux
+dist: focal
+compiler: gcc
+
+jobs:
+  include:
+    - name: FreeBSD x86_64 (Clang)
+      os: freebsd
+      compiler: clang
+      env:
+       - TARGET="shared"
+
+    - name: Linux s390x (GCC)
+      arch: s390x
+      env:
+       - TARGET="shared"
+
+    - name: Linux ppc64le (GCC)
+      arch: ppc64le
+      env:
+       - TARGET="shared"
+
+    - name: Linux arm64 (GCC)
+      arch: arm64
+      env:
+       - TARGET="shared"
+
+    - name: Linux arm32 cross (GCC)
+      arch: arm64
+      env:
+       - TARGET="cross-arm32"
+
+install:
+  - ./src/scripts/ci/setup_travis.sh
+
+script:
+  - ./src/scripts/ci_build.py --os=$TRAVIS_OS_NAME --cc=$CC --cc-bin=$CXX --without-pylint3 $EXTRA_FLAGS $TARGET
+
+# whitelist branches to avoid testing feature branches twice (as branch and as pull request)
+branches:
+  only:
+    - master
+    - release-2
+    - coverity_scan
+
+git:
+  depth: 10
+
+cache:
+  ccache: true
+
+addons:
+  coverity_scan:
+    project:
+      name: "randombit/botan"
+    notification_email: jack@randombit.net
+    build_command_prepend: "./configure.py --no-optimizations --with-zlib --with-openssl"
+    build_command: "make -j2"
+    branch_pattern: coverity_scan
diff --git a/src/scripts/ci_build.py b/src/scripts/ci_build.py
index fd7313023..56f62b13b 100755
--- a/src/scripts/ci_build.py
+++ b/src/scripts/ci_build.py
@@ -25,33 +25,6 @@ def get_concurrency():
     except ImportError:
         return def_concurrency
 
-def known_targets():
-    return [
-        'amalgamation',
-        'baremetal',
-        'bsi',
-        'coverage',
-        'cross-android-arm32',
-        'cross-android-arm64',
-        'cross-arm32',
-        'cross-arm64',
-        'cross-i386',
-        'cross-ios-arm64',
-        'cross-mips64',
-        'cross-ppc32',
-        'cross-ppc64',
-        'cross-win64',
-        'docs',
-        'fuzzers',
-        'lint',
-        'minimized',
-        'nist',
-        'sanitizer',
-        'shared',
-        'static',
-        'valgrind',
-    ]
-
 def build_targets(target, target_os):
     if target in ['shared', 'minimized', 'bsi', 'nist']:
         yield 'shared'
@@ -72,8 +45,7 @@ def build_targets(target, target_os):
         yield 'bogo_shim'
 
 def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
-                    ccache, root_dir, pkcs11_lib, use_gdb, disable_werror, extra_cxxflags,
-                    disabled_tests):
+                    ccache, root_dir, pkcs11_lib, use_gdb, disable_werror, extra_cxxflags):
     # pylint: disable=too-many-branches,too-many-statements,too-many-arguments,too-many-locals
 
     """
@@ -125,9 +97,6 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
     if target in ['minimized']:
         flags += ['--minimized-build', '--enable-modules=system_rng,sha2_32,sha2_64,aes']
 
-    if target in ['amalgamation']:
-        flags += ['--amalgamation']
-
     if target in ['bsi', 'nist']:
         # tls is optional for bsi/nist but add it so verify tests work with these minimized configs
         flags += ['--module-policy=%s' % (target), '--enable-modules=tls']
@@ -138,7 +107,7 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
 
     if target == 'cross-win64':
         # this test compiles under MinGW but fails when run under Wine
-        disabled_tests.append('certstor_system')
+        test_cmd += ['--skip-tests=certstor_system']
 
     if target == 'coverage':
         flags += ['--with-coverage-info', '--with-debug-info', '--test-mode']
@@ -158,7 +127,7 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
             'pbkdf', 'argon2', 'bcrypt', 'bcrypt_pbkdf', 'compression',
             'ed25519_sign', 'elgamal_keygen', 'x509_path_rsa_pss']
 
-        disabled_tests += slow_tests
+        test_cmd += ['--skip-tests=%s' % (','.join(slow_tests))]
 
     if target == 'fuzzers':
         flags += ['--unsafe-fuzzer-mode']
@@ -300,15 +269,9 @@ def determine_flags(target, target_os, target_cpu, target_cc, cc_bin,
     if test_cmd is None:
         run_test_command = None
     else:
-        if use_gdb:
-            disabled_tests.append("os_utils")
-
-        # render 'disabled_tests' array into test_cmd
-        if disabled_tests:
-            test_cmd += ['--skip-tests=%s' % (','.join(disabled_tests))]
-
         if use_gdb:
             (cmd, args) = test_cmd[0], test_cmd[1:]
+            args += ['--skip-tests=os_utils']
             run_test_command = test_prefix + ['gdb', cmd,
                                               '-ex', 'run %s' % (' '.join(args)),
                                               '-ex', 'bt',
@@ -374,8 +337,6 @@ def parse_args(args):
 
     parser.add_option('--os', default=default_os(),
                       help='Set the target os (default %default)')
-    parser.add_option('--cpu', default=None,
-                      help='Specify a target CPU platform')
     parser.add_option('--cc', default='gcc',
                       help='Set the target compiler type (default %default)')
     parser.add_option('--cc-bin', default=None,
@@ -389,8 +350,18 @@ def parse_args(args):
     parser.add_option('--extra-cxxflags', metavar='FLAGS', default=[], action='append',
                       help='Specify extra build flags')
 
-    parser.add_option('--disabled-tests', metavar='DISABLED_TESTS', default=[], action='append',
-                      help='Comma separated list of tests that should not be run')
+    parser.add_option('--cpu', default=None,
+                      help='Specify a target CPU platform')
+
+    parser.add_option('--with-debug', action='store_true', default=False,
+                      help='Include debug information')
+    parser.add_option('--amalgamation', action='store_true', default=False,
+                      help='Build via amalgamation')
+    parser.add_option('--disable-shared', action='store_true', default=False,
+                      help='Disable building shared libraries')
+
+    parser.add_option('--branch', metavar='B', default=None,
+                      help='Specify branch being built')
 
     parser.add_option('--dry-run', action='store_true', default=False,
                       help='Just show commands to be executed')
@@ -443,7 +414,6 @@ def main(args=None):
 
     if args is None:
         args = sys.argv
-
     print("Invoked as '%s'" % (' '.join(args)))
     (options, args) = parse_args(args)
 
@@ -453,10 +423,6 @@ def main(args=None):
 
     target = args[1]
 
-    if target not in known_targets():
-        print("Unknown target '%s'" % (target))
-        return 2
-
     if options.use_python3 is None:
         use_python3 = have_prog('python3')
     else:
@@ -529,7 +495,7 @@ def main(args=None):
             target, options.os, options.cpu, options.cc,
             options.cc_bin, options.compiler_cache, root_dir,
             options.pkcs11_lib, options.use_gdb, options.disable_werror,
-            options.extra_cxxflags, options.disabled_tests)
+            options.extra_cxxflags)
 
         cmds.append([py_interp, os.path.join(root_dir, 'configure.py')] + config_flags)
 
@@ -538,7 +504,6 @@ def main(args=None):
             make_cmd += ['-C', root_dir]
         if options.build_jobs > 1 and options.make_tool != 'nmake':
             make_cmd += ['-j%d' % (options.build_jobs)]
-
         make_cmd += ['-k']
 
         if target == 'docs':
diff --git a/src/scripts/install.py b/src/scripts/install.py
index 3e2f095ea..688d2828c 100755
--- a/src/scripts/install.py
+++ b/src/scripts/install.py
@@ -175,13 +175,6 @@ def main(args):
             soname_base = libname + '.dll'
             copy_executable(os.path.join(out_dir, soname_base),
                             prepend_destdir(os.path.join(bin_dir, soname_base)))
-        elif target_os == "mingw":
-            shared_lib_name = cfg['shared_lib_name']
-            copy_executable(os.path.join(out_dir, shared_lib_name),
-                            prepend_destdir(os.path.join(bin_dir, shared_lib_name)))
-            implib_name = shared_lib_name + '.a'
-            copy_executable(os.path.join(out_dir, implib_name),
-                            prepend_destdir(os.path.join(lib_dir, implib_name)))
         else:
             soname_patch = cfg['soname_patch']
             soname_abi = cfg['soname_abi']


Test patch:
diff --git a/src/tests/data/x509/misc/certstor/ca_bundle_containing_non_ca.pem b/src/tests/data/x509/misc/certstor/ca_bundle_containing_non_ca.pem
index f029ea39d..e6b723261 100644
--- a/src/tests/data/x509/misc/certstor/ca_bundle_containing_non_ca.pem
+++ b/src/tests/data/x509/misc/certstor/ca_bundle_containing_non_ca.pem
@@ -1,36 +1,25 @@
 
-> ISRG Root X1
+> DST Root CA X3
 
 -----BEGIN CERTIFICATE-----
-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
+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
 -----END CERTIFICATE-----
 
 > rmeusel-eduroam@cern.ch
diff --git a/src/tests/data/x509/misc/certstor/valid_ca_bundle.pem b/src/tests/data/x509/misc/certstor/valid_ca_bundle.pem
index a30919433..d1024179c 100644
--- a/src/tests/data/x509/misc/certstor/valid_ca_bundle.pem
+++ b/src/tests/data/x509/misc/certstor/valid_ca_bundle.pem
@@ -27,38 +27,27 @@ xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
 KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
 -----END CERTIFICATE-----
 
-> ISRG Root X1
+> DST Root CA X3
 
 -----BEGIN CERTIFICATE-----
-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
+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
 -----END CERTIFICATE-----
 
 > VeriSign Class 3 Public Primary Certification Authority - G3
diff --git a/src/tests/test_certstor_flatfile.cpp b/src/tests/test_certstor_flatfile.cpp
index 2d5107133..3c8177653 100644
--- a/src/tests/test_certstor_flatfile.cpp
+++ b/src/tests/test_certstor_flatfile.cpp
@@ -65,7 +65,7 @@ Test::Result find_certificate_by_pubkey_sha1()
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -99,7 +99,7 @@ Test::Result find_cert_by_subject_dn()
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -156,7 +156,7 @@ Test::Result find_cert_by_subject_dn_and_key_id()
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -185,7 +185,7 @@ Test::Result find_certs_by_subject_dn_and_key_id()
          {
          auto cns = certs.front().subject_dn().get_attribute("CN");
          result.test_int_eq("exactly one CN", cns.size(), 1);
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
diff --git a/src/tests/test_certstor_system.cpp b/src/tests/test_certstor_system.cpp
index 663d2064a..d84b3cf2b 100644
--- a/src/tests/test_certstor_system.cpp
+++ b/src/tests/test_certstor_system.cpp
@@ -33,7 +33,7 @@ Test::Result find_certificate_by_pubkey_sha1(Botan::Certificate_Store& certstore
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -96,7 +96,7 @@ Test::Result find_cert_by_subject_dn(Botan::Certificate_Store& certstore)
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -157,7 +157,7 @@ Test::Result find_cert_by_subject_dn_and_key_id(Botan::Certificate_Store& certst
          {
          auto cns = cert->subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -185,7 +185,7 @@ Test::Result find_certs_by_subject_dn_and_key_id(Botan::Certificate_Store& certs
          {
          auto cns = certs.front().subject_dn().get_attribute("CN");
          result.test_is_eq("exactly one CN", cns.size(), size_t(1));
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -222,7 +222,7 @@ Test::Result find_all_certs_by_subject_dn(Botan::Certificate_Store& certstore)
          {
          auto cns = certs.front().subject_dn().get_attribute("CN");
          result.test_gte("at least one CN", cns.size(), size_t(1));
-         result.test_eq("CN", cns.front(), get_subject_cn());
+         result.test_eq("CN", cns.front(), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
@@ -312,8 +312,8 @@ Test::Result certificate_matching_with_dn_normalization(Botan::Certificate_Store
       if(result.confirm("find_all_certs did find the skewed DN", !certs.empty()) &&
          result.confirm("find_cert did find the skewed DN", cert.has_value()))
          {
-         result.test_eq("it is the correct cert", certs.front().subject_dn().get_first_attribute("CN"), get_subject_cn());
-         result.test_eq("it is the correct cert", cert->subject_dn().get_first_attribute("CN"), get_subject_cn());
+         result.test_eq("it is the correct cert", certs.front().subject_dn().get_first_attribute("CN"), "DST Root CA X3");
+         result.test_eq("it is the correct cert", cert->subject_dn().get_first_attribute("CN"), "DST Root CA X3");
          }
       }
    catch(std::exception& e)
diff --git a/src/tests/test_certstor_utils.cpp b/src/tests/test_certstor_utils.cpp
index 8221addd9..509959650 100644
--- a/src/tests/test_certstor_utils.cpp
+++ b/src/tests/test_certstor_utils.cpp
@@ -24,13 +24,13 @@ Botan::X509_DN read_dn(const std::string hex)
 
 Botan::X509_DN get_dn()
    {
-   // ASN.1 encoded subject DN of "ISRG Root X1"
+   // ASN.1 encoded subject DN of "DST Root CA X3"
    // This certificate is in the standard "System Roots" of any macOS setup,
    // serves as the trust root of botan.randombit.net and expires on
-   // Monday, 4. June 2035 at 13:04:38 Central European Summer Time
-   return read_dn("304F310B300906035504061302555331293027060355040A1320496E74657"
-                  "26E65742053656375726974792052657365617263682047726F7570311530"
-                  "130603550403130C4953524720526F6F74205831");
+   // Thursday, 30. September 2021 at 16:01:15 Central European Summer Time
+   return read_dn("303f31243022060355040a131b4469676974616c205369676e6174757265"
+                  "20547275737420436f2e311730150603550403130e44535420526f6f7420"
+                  "4341205833");
    }
 
 Botan::X509_DN get_utf8_dn()
@@ -45,13 +45,8 @@ Botan::X509_DN get_utf8_dn()
 
 std::vector<uint8_t> get_key_id()
    {
-   // this is the same as the public key SHA1 of "ISRG Root X1"
-   return Botan::hex_decode("79B459E67BB6E5E40173800888C81A58F6E99B6E");
-   }
-
-std::string get_subject_cn()
-   {
-   return "ISRG Root X1";
+   // this is the same as the public key SHA1
+   return Botan::hex_decode("c4a7b1a47b2c71fadbe14b9075ffc41560858910");
    }
 
 
@@ -91,37 +86,9 @@ Botan::X509_DN get_skewed_dn()
    // according to Apple's idea of a normalized PrintableString field:
    //   (1) It has leading and trailing white space
    //   (2) It contains multiple spaces between 'words'
-   //
-   // This skewed DN was fabricated using the program below and the DN-info of
-   // "ISRG Root X1" which expires on Monday, 4. June 2035 at 13:04:38 CEST
-   //
-   // ```C++
-   // #include <iostream>
-   //
-   // #include <botan/pkix_types.h>
-   // #include <botan/der_enc.h>
-   // #include <botan/hex.h>
-   //
-   // using namespace Botan;
-   //
-   // int main()
-   //    {
-   //    X509_DN dn{};
-   //
-   //    dn.add_attribute(OID{2,5,4,6}, ASN1_String("US", ASN1_Type::PrintableString));
-   //    dn.add_attribute(OID{2,5,4,10}, ASN1_String("Internet Security  Research Group  ", ASN1_Type::PrintableString));
-   //    dn.add_attribute(OID{2,5,4,3}, ASN1_String("  ISRG Root  X1", ASN1_Type::PrintableString));
-   //
-   //    DER_Encoder enc;
-   //    dn.encode_into(enc);
-   //
-   //    std::cout << hex_encode(enc.get_contents()) << std::endl;
-   //    }
-   // ```
-
-   return read_dn("3055310B3009060355040613025553312C302A060355040A1323496E74657"
-                  "26E6574205365637572697479202052657365617263682047726F75702020"
-                  "311830160603550403130F20204953524720526F6F7420205831");
+   return read_dn("304b312a3028060355040a132120204469676974616c2020205369676e61"
+                  "7475726520547275737420436f2e2020311d301b06035504031314202044"
+                  "5354202020526f6f742043412058332020");
    }
 
 std::vector<uint8_t> get_unknown_key_id()
diff --git a/src/tests/test_certstor_utils.h b/src/tests/test_certstor_utils.h
index 1db9edf17..d1c46111d 100644
--- a/src/tests/test_certstor_utils.h
+++ b/src/tests/test_certstor_utils.h
@@ -26,7 +26,6 @@ Botan::X509_DN get_dn();
 Botan::X509_DN get_utf8_dn();
 
 std::vector<uint8_t> get_key_id();
-std::string get_subject_cn();
 
 std::vector<uint8_t> get_pubkey_sha1_of_cert_with_different_key_id();
 Botan::X509_DN       get_dn_of_cert_with_different_key_id();
diff --git a/src/tests/test_os_utils.cpp b/src/tests/test_os_utils.cpp
index ad83c95b1..92386114c 100644
--- a/src/tests/test_os_utils.cpp
+++ b/src/tests/test_os_utils.cpp
@@ -112,11 +112,12 @@ class OS_Utils_Tests final : public Test
 
       Test::Result test_get_cpu_numbers()
          {
-         Test::Result result("OS::get_cpu_available");
+         Test::Result result("OS::get_cpu_total/OS::get_cpu_available");
 
-         const size_t ta = Botan::OS::get_cpu_available();
+         size_t tt = Botan::OS::get_cpu_total();
+         size_t ta = Botan::OS::get_cpu_available();
 
-         result.test_gte("get_cpu_available is at least 1", ta, 1);
+         result.test_lte("get_cpu_available not greater than total", ta, tt);
 
          return result;
          }
diff --git a/src/tests/unit_ecdsa.cpp b/src/tests/unit_ecdsa.cpp
index f0ccc08f8..83e6e3a3e 100644
--- a/src/tests/unit_ecdsa.cpp
+++ b/src/tests/unit_ecdsa.cpp
@@ -33,7 +33,7 @@ namespace {
 #if defined(BOTAN_HAS_ECDSA)
 
 /**
-* Tests whether the signing routine will work correctly in case
+* Tests whether the the signing routine will work correctly in case
 * the integer e that is constructed from the message (thus the hash
 * value) is larger than n, the order of the base point.  Tests the
 * signing function of the pk signer object