Repository: randombit/botan (cpp)

Issue:
CLI assumes that some RNG type is available
While trying to customize the Botan build to our product, I stumbled over a build issue with the following configuration:

```
./configure.py --minimized-build --enable-modules=tls,asio --with-boost [... boost specific extras ...]
```

```
src/cli/tls_proxy.cpp:28:10: fatal error: 'botan/auto_rng.h' file not found
#include <botan/auto_rng.h>
         ^~~~~~~~~~~~~~~~~~

src/cli/tls_http_server.cpp:36:13: fatal error: 'botan/auto_rng.h' file not found
#include <botan/auto_rng.h>
         ^~~~~~~~~~~~~~~~~~
```

Adding `auto_rng` to the list of enabled modules fixes the compilation issue, of course.

The output of the above-mentioned `./configure.py` looks like that:

```
   INFO: Autodetected platform information: OS="Darwin" machine="x86_64" proc="i386"
   INFO: Using /etc/ssl/cert.pem as system certificate store
   INFO: Auto-detected compiler version 4.0
   INFO: Auto-detected compiler arch x86_64
   INFO: Target is clang:4.0-macos-x86_64
   INFO: Skipping (incompatible CPU): aes_armv8 aes_power8 pmull sha1_armv8 sha2_32_armv8 sm4_armv8
   INFO: Skipping (incompatible OS): certstor_system_windows proc_walk win32_stats
   INFO: Skipping (not requested): adler32 aes_ni aes_ssse3 aont argon2 aria auto_rng base32 base58 bcrypt bcrypt_pbkdf blake2 blowfish camellia cascade cast128 cast256 cbc cbc_mac ccm cecpq1 certstor_flatfile certstor_sql certstor_sqlite3 certstor_system certstor_system_macos cfb chacha chacha20poly1305 chacha_avx2 chacha_rng chacha_simd32 checksum clmul clmul_ssse3 cmac codec_filt comb4p compression crc24 crc32 cryptobox curve25519 des dev_random dlies dsa dyn_load eax ecgdsa ecies eckcdsa ed25519 elgamal eme_oaep eme_raw emsa_raw emsa_x931 fd_unix ffi filters fpe_fe1 getentropy gmac gost_28147 gost_3410 gost_3411 hkdf hmac_drbg hotp http_util idea idea_sse2 iso9796 kasumi kdf1 kdf1_iso18033 kdf2 keccak lion locking_allocator mce mceies md4 mem_pool misty1 mode_pad newhope nist_keywrap noekeon noekeon_simd ocb ofb passhash9 pbes2 pbkdf pbkdf1 pbkdf2 pgp_s2k pkcs11 poly1305 poly_dbl prf_x942 psk_db rc4 rdrand rdrand_rng rdseed rfc3394 rfc6979 rmd160 salsa20 scrypt seed serpent serpent_avx2 serpent_simd sessions_sql sessions_sqlite3 sha1_sse2 sha1_x86 sha2_32_bmi2 sha2_32_x86 sha2_64_bmi2 sha3 sha3_bmi2 shacal2 shacal2_simd shacal2_x86 shake shake_cipher simd simd_avx2 siphash siv skein sm2 sm3 sm4 socket sodium sp800_108 sp800_56a sp800_56c srp6 stateful_rng streebog system_rng thread_utils threefish_512 threefish_512_avx2 tiger tls_cbc tss twofish uuid whirlpool x919_mac xmss xtea xts
   INFO: Skipping (requires external dependency): bearssl bzip2 commoncrypto lzma openssl sqlite3 tpm zlib
   INFO: Enabling use of external dependency boost
   INFO: Loading modules: aead aes asio asn1 base base64 bigint block boost cpuid ctr dh dl_algo dl_group ec_group ecc_key ecdh ecdsa eme_pkcs1 emsa1 emsa_pkcs1 emsa_pssr entropy gcm hash hash_id hex hmac kdf keypair mac md5 mdx_hash mgf1 modes mp numbertheory par_hash pem pk_pad prf_tls pubkey rng rsa sha1 sha2_32 sha2_64 stream tls utils x509
   INFO: Defaulting to assuming little endian
   INFO: Using symlink to link files into build dir (use --link-method to change)
   INFO: Botan 2.11.0 (revision git:16a726c3ad10316bd8d37b6118a5cc52894e8e8f) (unreleased undated) build setup is complete
```

Pull request:
Don't assume any particular kind of RNG is available in the cli
Closes #2085

Patch:
diff --git a/src/cli/cli.h b/src/cli/cli.h
index 2a7bef483..6ddf34d02 100644
--- a/src/cli/cli.h
+++ b/src/cli/cli.h
@@ -28,7 +28,7 @@ class Argument_Parser;
 
 /* Declared in cli_rng.cpp */
 std::unique_ptr<Botan::RandomNumberGenerator>
-cli_make_rng(const std::string& type, const std::string& hex_drbg_seed);
+cli_make_rng(const std::string& type = "", const std::string& hex_drbg_seed = "");
 
 class Command
    {
diff --git a/src/cli/cli_rng.cpp b/src/cli/cli_rng.cpp
index a7210f27d..2fea7ec65 100644
--- a/src/cli/cli_rng.cpp
+++ b/src/cli/cli_rng.cpp
@@ -39,16 +39,6 @@ cli_make_rng(const std::string& rng_type, const std::string& hex_drbg_seed)
       }
 #endif
 
-#if defined(BOTAN_HAS_RDRAND_RNG)
-   if(rng_type == "rdrand")
-      {
-      if(Botan::CPUID::has_rdrand())
-         return std::unique_ptr<Botan::RandomNumberGenerator>(new Botan::RDRAND_RNG);
-      else
-         throw CLI_Error("RDRAND instruction not supported on this processor");
-      }
-#endif
-
    const std::vector<uint8_t> drbg_seed = Botan::hex_decode(hex_drbg_seed);
 
 #if defined(BOTAN_HAS_AUTO_SEEDING_RNG)
@@ -68,7 +58,7 @@ cli_make_rng(const std::string& rng_type, const std::string& hex_drbg_seed)
 #endif
 
 #if defined(BOTAN_HAS_HMAC_DRBG) && defined(BOTAN_HAS_SHA2_32)
-   if(rng_type == "drbg")
+   if(rng_type == "drbg" || (rng_type.empty() && drbg_seed.empty() == false))
       {
       std::unique_ptr<Botan::MessageAuthenticationCode> mac =
          Botan::MessageAuthenticationCode::create_or_throw("HMAC(SHA-256)");
@@ -84,7 +74,20 @@ cli_make_rng(const std::string& rng_type, const std::string& hex_drbg_seed)
       }
 #endif
 
-   throw CLI_Error_Unsupported("RNG", rng_type);
+#if defined(BOTAN_HAS_RDRAND_RNG)
+   if(rng_type == "rdrand" || rng_type.empty())
+      {
+      if(Botan::CPUID::has_rdrand())
+         return std::unique_ptr<Botan::RandomNumberGenerator>(new Botan::RDRAND_RNG);
+      else if(rng_type.empty() == false)
+         throw CLI_Error("RDRAND instruction not supported on this processor");
+      }
+#endif
+
+   if(rng_type.empty())
+      throw CLI_Error_Unsupported("No random number generator seems to be available in the current build");
+   else
+      throw CLI_Error_Unsupported("RNG", rng_type);
    }
 
 class RNG final : public Command
diff --git a/src/cli/tls_http_server.cpp b/src/cli/tls_http_server.cpp
index 30194a73c..b6961b9df 100644
--- a/src/cli/tls_http_server.cpp
+++ b/src/cli/tls_http_server.cpp
@@ -1,5 +1,5 @@
 /*
-* (C) 2014,2015,2017 Jack Lloyd
+* (C) 2014,2015,2017,2019 Jack Lloyd
 * (C) 2016 Matthias Gierlings
 *
 * Botan is released under the Simplified BSD License (see license.txt)
@@ -30,12 +30,6 @@
 #include <botan/version.h>
 #include <botan/hex.h>
 
-#if defined(BOTAN_HAS_SYSTEM_RNG)
-   #include <botan/system_rng.h>
-#else
-   #include <botan/auto_rng.h>
-#endif
-
 #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
    #include <botan/tls_session_manager_sqlite.h>
 #endif
@@ -213,7 +207,8 @@ class TLS_Asio_HTTP_Session final : public boost::enable_shared_from_this<TLS_As
                             Botan::TLS::Policy& policy)
          : m_strand(io)
          , m_client_socket(io)
-         , m_tls(*this, session_manager, credentials, policy, m_rng) {}
+         , m_rng(cli_make_rng())
+         , m_tls(*this, session_manager, credentials, policy, *m_rng) {}
 
       void client_read(const boost::system::error_code& error,
                        size_t bytes_transferred)
@@ -415,11 +410,7 @@ class TLS_Asio_HTTP_Session final : public boost::enable_shared_from_this<TLS_As
 
       tcp::socket m_client_socket;
 
-#if defined(BOTAN_HAS_SYSTEM_RNG)
-      Botan::System_RNG m_rng;
-#else
-      Botan::AutoSeeded_RNG m_rng;
-#endif
+      std::unique_ptr<Botan::RandomNumberGenerator> m_rng;
       Botan::TLS::Server m_tls;
       std::string m_chello_summary;
       std::string m_session_summary;
diff --git a/src/cli/tls_proxy.cpp b/src/cli/tls_proxy.cpp
index ad199eb91..d7cc7da68 100644
--- a/src/cli/tls_proxy.cpp
+++ b/src/cli/tls_proxy.cpp
@@ -1,6 +1,6 @@
 /*
 * TLS Server Proxy
-* (C) 2014,2015 Jack Lloyd
+* (C) 2014,2015,2019 Jack Lloyd
 * (C) 2016 Matthias Gierlings
 *
 * Botan is released under the Simplified BSD License (see license.txt)
@@ -27,12 +27,6 @@
 #include <botan/pkcs8.h>
 #include <botan/hex.h>
 
-#if defined(BOTAN_HAS_SYSTEM_RNG)
-   #include <botan/system_rng.h>
-#else
-   #include <botan/auto_rng.h>
-#endif
-
 #if defined(BOTAN_HAS_TLS_SQLITE3_SESSION_MANAGER)
    #include <botan/tls_session_manager_sqlite.h>
 #endif
@@ -156,11 +150,12 @@ class tls_proxy_session final : public boost::enable_shared_from_this<tls_proxy_
          , m_server_endpoints(endpoints)
          , m_client_socket(io)
          , m_server_socket(io)
+         , m_rng(cli_make_rng())
          , m_tls(*this,
                  session_manager,
                  credentials,
                  policy,
-                 m_rng) {}
+                 *m_rng) {}
 
       void client_read(const boost::system::error_code& error,
                        size_t bytes_transferred)
@@ -353,11 +348,7 @@ class tls_proxy_session final : public boost::enable_shared_from_this<tls_proxy_
       tcp::socket m_client_socket;
       tcp::socket m_server_socket;
 
-#if defined(BOTAN_HAS_SYSTEM_RNG)
-      Botan::System_RNG m_rng;
-#else
-      Botan::AutoSeeded_RNG m_rng;
-#endif
+      std::unique_ptr<Botan::RandomNumberGenerator> m_rng;
       Botan::TLS::Server m_tls;
       std::string m_hostname;
 


Test patch:
diff --git a/src/cli/timing_tests.cpp b/src/cli/timing_tests.cpp
index b1c5b0bd7..01dd61596 100644
--- a/src/cli/timing_tests.cpp
+++ b/src/cli/timing_tests.cpp
@@ -12,7 +12,7 @@
 *
 * (C) 2016 Juraj Somorovsky - juraj.somorovsky@hackmanit.de
 * (C) 2017 Neverhub
-* (C) 2017,2018 Jack Lloyd
+* (C) 2017,2018,2019 Jack Lloyd
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
@@ -22,6 +22,7 @@
 #include <sstream>
 #include <fstream>
 
+#include <botan/rng.h>
 #include <botan/internal/os_utils.h>
 
 #if defined(BOTAN_HAS_BIGINT)
@@ -40,14 +41,6 @@
    #include <botan/dl_group.h>
 #endif
 
-#if defined(BOTAN_HAS_SYSTEM_RNG)
-   #include <botan/system_rng.h>
-#endif
-
-#if defined(BOTAN_HAS_AUTO_SEEDING_RNG) && defined(BOTAN_AUTO_RNG_HMAC)
-   #include <botan/auto_rng.h>
-#endif
-
 #if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EME_RAW)
    #include <botan/pubkey.h>
    #include <botan/rsa.h>
@@ -70,7 +63,16 @@ typedef uint64_t ticks;
 class Timing_Test
    {
    public:
-      Timing_Test() = default;
+      Timing_Test()
+         {
+         /*
+         A constant seed is ok here since the timing test rng just needs to be
+         "random" but not cryptographically secure - even std::rand() would be ok.
+         */
+         const std::string drbg_seed(64, '*');
+         m_rng = cli_make_rng("", drbg_seed); // throws if it can't find anything to use
+         }
+
       virtual ~Timing_Test() = default;
 
       std::vector<std::vector<ticks>> execute_evaluation(
@@ -92,19 +94,13 @@ class Timing_Test
          return Botan::OS::get_high_resolution_clock();
          }
 
-      static Botan::RandomNumberGenerator& timing_test_rng()
+      Botan::RandomNumberGenerator& timing_test_rng()
          {
-#if defined(BOTAN_HAS_SYSTEM_RNG)
-         return Botan::system_rng();
-#elif defined(BOTAN_HAS_AUTO_SEEDING_RNG) && defined(BOTAN_AUTO_RNG_HMAC)
-         static Botan::AutoSeeded_RNG static_timing_test_rng;
-         return static_timing_test_rng;
-#else
-         // we could just use SHA-256 in OFB mode for these purposes
-         throw CLI_Error("Timing tests require a PRNG");
-#endif
+         return (*m_rng);
          }
 
+   private:
+      std::unique_ptr<Botan::RandomNumberGenerator> m_rng;
    };
 
 #if defined(BOTAN_HAS_RSA) && defined(BOTAN_HAS_EME_PKCS1) && defined(BOTAN_HAS_EME_RAW)
@@ -113,22 +109,22 @@ class Bleichenbacker_Timing_Test final : public Timing_Test
    {
    public:
       Bleichenbacker_Timing_Test(size_t keysize)
-         : m_privkey(Timing_Test::timing_test_rng(), keysize)
+         : m_privkey(timing_test_rng(), keysize)
          , m_pubkey(m_privkey)
-         , m_enc(m_pubkey, Timing_Test::timing_test_rng(), "Raw")
-         , m_dec(m_privkey, Timing_Test::timing_test_rng(), "PKCS1v15") {}
+         , m_enc(m_pubkey, timing_test_rng(), "Raw")
+         , m_dec(m_privkey, timing_test_rng(), "PKCS1v15") {}
 
       std::vector<uint8_t> prepare_input(std::string input) override
          {
          const std::vector<uint8_t> input_vector = Botan::hex_decode(input);
-         const std::vector<uint8_t> encrypted = m_enc.encrypt(input_vector, Timing_Test::timing_test_rng());
+         const std::vector<uint8_t> encrypted = m_enc.encrypt(input_vector, timing_test_rng());
          return encrypted;
          }
 
       ticks measure_critical_function(std::vector<uint8_t> input) override
          {
          const ticks start = get_ticks();
-         m_dec.decrypt_or_random(input.data(), m_ctext_length, m_expected_content_size, Timing_Test::timing_test_rng());
+         m_dec.decrypt_or_random(input.data(), m_ctext_length, m_expected_content_size, timing_test_rng());
          const ticks end = get_ticks();
          return (end - start);
          }
@@ -157,15 +153,15 @@ class Manger_Timing_Test final : public Timing_Test
    {
    public:
       Manger_Timing_Test(size_t keysize)
-         : m_privkey(Timing_Test::timing_test_rng(), keysize)
+         : m_privkey(timing_test_rng(), keysize)
          , m_pubkey(m_privkey)
-         , m_enc(m_pubkey, Timing_Test::timing_test_rng(), m_encrypt_padding)
-         , m_dec(m_privkey, Timing_Test::timing_test_rng(), m_decrypt_padding) {}
+         , m_enc(m_pubkey, timing_test_rng(), m_encrypt_padding)
+         , m_dec(m_privkey, timing_test_rng(), m_decrypt_padding) {}
 
       std::vector<uint8_t> prepare_input(std::string input) override
          {
          const std::vector<uint8_t> input_vector = Botan::hex_decode(input);
-         const std::vector<uint8_t> encrypted = m_enc.encrypt(input_vector, Timing_Test::timing_test_rng());
+         const std::vector<uint8_t> encrypted = m_enc.encrypt(input_vector, timing_test_rng());
          return encrypted;
          }
 
@@ -278,7 +274,7 @@ class ECDSA_Timing_Test final : public Timing_Test
 
 ECDSA_Timing_Test::ECDSA_Timing_Test(std::string ecgroup)
    : m_group(ecgroup)
-   , m_privkey(Timing_Test::timing_test_rng(), m_group)
+   , m_privkey(timing_test_rng(), m_group)
    , m_x(m_privkey.private_value())
    {}
 
@@ -292,7 +288,7 @@ ticks ECDSA_Timing_Test::measure_critical_function(std::vector<uint8_t> input)
    //The following ECDSA operations involve and should not leak any information about k.
 
    const Botan::BigInt k_inv = m_group.inverse_mod_order(k);
-   const Botan::PointGFp k_times_P = m_group.blinded_base_point_multiply(k, Timing_Test::timing_test_rng(), m_ws);
+   const Botan::PointGFp k_times_P = m_group.blinded_base_point_multiply(k, timing_test_rng(), m_ws);
    const Botan::BigInt r = m_group.mod_order(k_times_P.get_affine_x());
    const Botan::BigInt s = m_group.multiply_mod_order(k_inv, mul_add(m_x, r, msg));
 
@@ -327,7 +323,7 @@ ticks ECC_Mul_Timing_Test::measure_critical_function(std::vector<uint8_t> input)
 
    ticks start = get_ticks();
 
-   const Botan::PointGFp k_times_P = m_group.blinded_base_point_multiply(k, Timing_Test::timing_test_rng(), m_ws);
+   const Botan::PointGFp k_times_P = m_group.blinded_base_point_multiply(k, timing_test_rng(), m_ws);
 
    ticks end = get_ticks();