diff --git a/.travis.yml b/.travis.yml
index d761afc5..00b2cdee 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -129,6 +129,7 @@ install:
- export PATH="`pwd`":$PATH
- git submodule update --init tools/build
- git submodule update --init tools/boostdep
+ - git submodule update --init libs/align
- git submodule update --init libs/asio
- git submodule update --init libs/assert
- git submodule update --init libs/config
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e702e5de..f8d7cbf9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,7 @@ Version 176:
* Tidy up Quick Reference
* Fix array end calculation in utf8 assertion
+* WebSocket masks use secure PRNG by default
--------------------------------------------------------------------------------
diff --git a/appveyor.yml b/appveyor.yml
index 179f8fbe..9522ca0d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -23,6 +23,7 @@ install:
- cd boost-root
- git submodule update --init tools/build
- git submodule update --init tools/boostdep
+ - git submodule update --init libs/align
- git submodule update --init libs/asio
- git submodule update --init libs/assert
- git submodule update --init libs/config
diff --git a/doc/qbk/09_releases.qbk b/doc/qbk/09_releases.qbk
index 1e959853..37324eb8 100644
--- a/doc/qbk/09_releases.qbk
+++ b/doc/qbk/09_releases.qbk
@@ -10,8 +10,11 @@
[section Release Notes]
This version fixes a missing executor work guard in all composed operations
-used in the implementatio. Users who are experiencing crashes related to
-asynchronous completion handlers are encouraged to upgrade.
+used in the implementation. Users who are experiencing crashes related to
+asynchronous completion handlers are encouraged to upgrade. Also included
+is an improved mechanism for generating random numbers used to mask outgoing
+websocket frames when operating in the client mode. This resolves a
+vulnerability described in the Beast Hybrid Assessment Report from Bishop Fox.
[heading Boost 1.68]
@@ -35,14 +38,20 @@ in future versions.
* New [link beast.ref.boost__beast__http__is_mutable_body_writer `http::is_mutable_body_writer`] metafunction
+* New [link beast.ref.boost__beast__websocket__seed_prng `websocket::seed_prng`] for manually providing entropy to the PRNG
+
+* New [link beast.ref.boost__beast__websocket__stream.secure_prng `websocket::stream::secure_prng`] to control whether the connection uses a secure PRNG
+
[*Improvements]
+* Generated WebSocket masks use a secure PRNG by default
+
+* Improvements to [link beast.ref.boost__beast__buffers_adapter `buffers_adapter`]
+
* ([issue 1109]) Use a shared string for example HTTP server doc roots
* ([issue 1079]) Add [link beast.ref.boost__beast__handler_ptr.has_value `handler_ptr::has_value`]
-* Improvements to [link beast.ref.boost__beast__buffers_adapter `buffers_adapter`]
-
[*Fixes]
* ([issue 1073]) Fix race in advanced server examples
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 4c84b64b..c5d9bef7 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -137,6 +137,7 @@
async_teardown
is_upgrade
+ seed_prng
teardown
Options
diff --git a/include/boost/beast/core/detail/chacha.hpp b/include/boost/beast/core/detail/chacha.hpp
new file mode 100644
index 00000000..976ade56
--- /dev/null
+++ b/include/boost/beast/core/detail/chacha.hpp
@@ -0,0 +1,196 @@
+//
+// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/boostorg/beast
+//
+
+//
+// This is a derivative work, original copyright follows:
+//
+
+/*
+ Copyright (c) 2015 Orson Peters
+
+ This software is provided 'as-is', without any express or implied warranty. In no event will the
+ authors be held liable for any damages arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose, including commercial
+ applications, and to alter it and redistribute it freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not claim that you wrote the
+ original software. If you use this software in a product, an acknowledgment in the product
+ documentation would be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be misrepresented as
+ being the original software.
+
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#ifndef BOOST_BEAST_CORE_DETAIL_CHACHA_HPP
+#define BOOST_BEAST_CORE_DETAIL_CHACHA_HPP
+
+#include
+#include
+#include
+
+namespace boost {
+namespace beast {
+namespace detail {
+
+template
+class chacha
+{
+ void generate_block();
+ void chacha_core();
+
+ alignas(16) std::uint32_t block_[16];
+ std::uint32_t keysetup_[8];
+ std::uint64_t ctr_ = 0;
+ int idx_ = 16;
+
+public:
+ static constexpr std::size_t state_size = sizeof(chacha::keysetup_);
+
+ using result_type = std::uint32_t;
+
+ chacha(std::uint32_t const* v, std::uint64_t stream);
+
+ std::uint32_t
+ operator()();
+
+#if 0
+ template
+ friend
+ bool
+ operator==(chacha const& lhs, chacha const& rhs);
+
+ template
+ friend
+ bool
+ operator!=(chacha const& lhs, chacha const& rhs);
+
+ static
+ constexpr
+ std::uint32_t
+ min()
+ {
+ return (std::numeric_limits::min)();
+ }
+
+ static
+ constexpr
+ std::uint32_t
+ max()
+ {
+ return (std::numeric_limits::max)();
+ }
+#endif
+};
+
+template
+chacha::
+chacha(std::uint32_t const* v, std::uint64_t stream)
+{
+ for (int i = 0; i < 6; ++i)
+ keysetup_[i] = v[i];
+ keysetup_[6] = v[6] + (stream & 0xffffffff);
+ keysetup_[7] = v[7] + ((stream >> 32) & 0xffffffff);
+}
+
+template
+std::uint32_t
+chacha::
+operator()()
+{
+ if(idx_ == 16)
+ {
+ idx_ = 0;
+ ++ctr_;
+ generate_block();
+ }
+ return block_[idx_++];
+}
+
+template
+void
+chacha::
+generate_block()
+{
+ std::uint32_t constexpr constants[4] = {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 };
+ std::uint32_t input[16];
+ for (int i = 0; i < 4; ++i)
+ input[i] = constants[i];
+ for (int i = 0; i < 8; ++i)
+ input[4 + i] = keysetup_[i];
+ input[12] = (ctr_ / 16) & 0xffffffffu;
+ input[13] = (ctr_ / 16) >> 32;
+ input[14] = input[15] = 0xdeadbeef; // Could use 128-bit counter.
+ for (int i = 0; i < 16; ++i)
+ block_[i] = input[i];
+ chacha_core();
+ for (int i = 0; i < 16; ++i)
+ block_[i] += input[i];
+}
+
+template
+void
+chacha::
+chacha_core()
+{
+ #define BOOST_BEAST_CHACHA_ROTL32(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+ #define BOOST_BEAST_CHACHA_QUARTERROUND(x, a, b, c, d) \
+ x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = BOOST_BEAST_CHACHA_ROTL32(x[d], 16); \
+ x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = BOOST_BEAST_CHACHA_ROTL32(x[b], 12); \
+ x[a] = x[a] + x[b]; x[d] ^= x[a]; x[d] = BOOST_BEAST_CHACHA_ROTL32(x[d], 8); \
+ x[c] = x[c] + x[d]; x[b] ^= x[c]; x[b] = BOOST_BEAST_CHACHA_ROTL32(x[b], 7)
+
+ for (unsigned i = 0; i < R; i += 2)
+ {
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 0, 4, 8, 12);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 1, 5, 9, 13);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 2, 6, 10, 14);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 3, 7, 11, 15);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 0, 5, 10, 15);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 1, 6, 11, 12);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 2, 7, 8, 13);
+ BOOST_BEAST_CHACHA_QUARTERROUND(block_, 3, 4, 9, 14);
+ }
+
+ #undef BOOST_BEAST_CHACHA_QUARTERROUND
+ #undef BOOST_BEAST_CHACHA_ROTL32
+}
+
+//#endif
+
+#if 0
+// Implement interface.
+
+template
+bool
+operator==(chacha const& lhs, chacha const& rhs)
+{
+ for (int i = 0; i < 8; ++i)
+ if (lhs.keysetup_[i] != rhs.keysetup_[i])
+ return false;
+ return lhs.ctr_ == rhs.ctr_;
+}
+
+template
+bool
+operator!=(chacha const& lhs, chacha const& rhs)
+{
+ return !(lhs == rhs);
+}
+#endif
+
+} // detail
+} // beast
+} // boost
+
+#endif
diff --git a/include/boost/beast/websocket/detail/hybi13.hpp b/include/boost/beast/websocket/detail/hybi13.hpp
index b9c67b82..424a9cc9 100644
--- a/include/boost/beast/websocket/detail/hybi13.hpp
+++ b/include/boost/beast/websocket/detail/hybi13.hpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -31,14 +32,15 @@ using sec_ws_key_type = static_string<
using sec_ws_accept_type = static_string<
beast::detail::base64::encoded_size(20)>;
-template
+inline
void
-make_sec_ws_key(sec_ws_key_type& key, Gen& g)
+make_sec_ws_key(sec_ws_key_type& key)
{
+ auto p = stream_prng::prng();
char a[16];
for(int i = 0; i < 16; i += 4)
{
- auto const v = g();
+ auto const v = p->secure();
a[i ] = v & 0xff;
a[i+1] = (v >> 8) & 0xff;
a[i+2] = (v >> 16) & 0xff;
diff --git a/include/boost/beast/websocket/detail/mask.hpp b/include/boost/beast/websocket/detail/mask.hpp
index 8958d793..2da2c9b4 100644
--- a/include/boost/beast/websocket/detail/mask.hpp
+++ b/include/boost/beast/websocket/detail/mask.hpp
@@ -24,66 +24,6 @@ namespace beast {
namespace websocket {
namespace detail {
-// Pseudo-random source of mask keys
-//
-template
-class maskgen_t
-{
- Generator g_;
-
-public:
- using result_type =
- typename Generator::result_type;
-
- maskgen_t();
-
- result_type
- operator()() noexcept;
-
- void
- rekey();
-};
-
-template
-maskgen_t::maskgen_t()
-{
- rekey();
-}
-
-template
-auto
-maskgen_t::operator()() noexcept ->
- result_type
-{
- for(;;)
- if(auto key = g_())
- return key;
-}
-
-template
-void
-maskgen_t<_>::rekey()
-{
- std::random_device rng;
-#if 0
- std::array e;
- for(auto& i : e)
- i = rng();
- // VFALCO This constructor causes
- // address sanitizer to fail, no idea why.
- std::seed_seq ss(e.begin(), e.end());
- g_.seed(ss);
-#else
- g_.seed(rng());
-#endif
-}
-
-// VFALCO NOTE This generator has 5KB of state!
-//using maskgen = maskgen_t;
-using maskgen = maskgen_t;
-
-//------------------------------------------------------------------------------
-
using prepared_key = std::array;
inline
diff --git a/include/boost/beast/websocket/detail/stream_base.hpp b/include/boost/beast/websocket/detail/stream_base.hpp
index 2e93cce3..db89dd17 100644
--- a/include/boost/beast/websocket/detail/stream_base.hpp
+++ b/include/boost/beast/websocket/detail/stream_base.hpp
@@ -16,9 +16,23 @@
#include
#include
#include
+#include
+#include
+#include
#include
+#include
#include
#include
+#include
+#include
+
+// Turn this on to avoid using thread_local
+//#define BOOST_BEAST_NO_THREAD_LOCAL 1
+
+#ifdef BOOST_BEAST_NO_THREAD_LOCAL
+#include
+#include
+#endif
namespace boost {
namespace beast {
@@ -105,8 +119,191 @@ public:
}
};
+//------------------------------------------------------------------------------
+
+struct stream_prng
+{
+ bool secure_prng_ = true;
+
+ struct prng_type
+ {
+ std::minstd_rand fast;
+ beast::detail::chacha<20> secure;
+
+#if BOOST_BEAST_NO_THREAD_LOCAL
+ prng_type* next = nullptr;
+#endif
+
+ prng_type(std::uint32_t const* v, std::uint64_t stream)
+ : fast(static_cast(
+ v[0] + v[1] + v[2] + v[3] + v[4] + v[5] + v[6] + v[7] + stream))
+ , secure(v, stream)
+ {
+ }
+ };
+
+ class prng_ref
+ {
+ prng_type* p_;
+
+ public:
+ prng_ref& operator=(prng_ref&&) = delete;
+
+ explicit
+ prng_ref(prng_type& p)
+ : p_(&p)
+ {
+ }
+
+ prng_ref(prng_ref&& other)
+ : p_([&other]
+ {
+ auto p = other.p_;
+ other.p_ = nullptr;
+ return p;
+ }())
+ {
+ }
+
+#ifdef BOOST_BEAST_NO_THREAD_LOCAL
+ ~prng_ref()
+ {
+ if(p_)
+ pool::impl().release(*p_);
+ }
+#endif
+
+ prng_type*
+ operator->() const
+ {
+ return p_;
+ }
+ };
+
+#ifndef BOOST_BEAST_NO_THREAD_LOCAL
+ static
+ prng_ref
+ prng()
+ {
+ static std::atomic stream{0};
+ thread_local prng_type p{seed(), stream++};
+ return prng_ref(p);
+ }
+
+#else
+ static
+ prng_ref
+ prng()
+ {
+ return prng_ref(pool::impl().acquire());
+ }
+
+#endif
+
+ static
+ std::uint32_t const*
+ seed(std::seed_seq* ss = nullptr)
+ {
+ static seed_data d(ss);
+ return d.v;
+ }
+
+ std::uint32_t
+ create_mask()
+ {
+ auto p = prng();
+ if(secure_prng_)
+ for(;;)
+ if(auto key = p->secure())
+ return key;
+ for(;;)
+ if(auto key = p->fast())
+ return key;
+ }
+
+private:
+ struct seed_data
+ {
+ std::uint32_t v[8];
+
+ explicit
+ seed_data(std::seed_seq* pss)
+ {
+ if(! pss)
+ {
+ std::random_device g;
+ std::seed_seq ss{
+ g(), g(), g(), g(), g(), g(), g(), g()};
+ ss.generate(v, v+8);
+ }
+ else
+ {
+ pss->generate(v, v+8);
+ }
+ }
+ };
+
+#ifdef BOOST_BEAST_NO_THREAD_LOCAL
+ class pool
+ {
+ prng_type* head_ = nullptr;
+ std::atomic n_{0};
+ std::mutex m_;
+
+ public:
+ ~pool()
+ {
+ for(auto p = head_; p;)
+ {
+ auto next = p->next;
+ p->~prng_type();
+ boost::alignment::aligned_free(p);
+ p = next;
+ }
+ }
+
+ prng_type&
+ acquire()
+ {
+ for(;;)
+ {
+ std::lock_guard lock(m_);
+ if(! head_)
+ break;
+ auto p = head_;
+ head_ = head_->next;
+ return *p;
+ }
+ auto p = boost::alignment::aligned_alloc(
+ 16, sizeof(prng_type));
+ if(! p)
+ BOOST_THROW_EXCEPTION(std::bad_alloc{});
+ return *(new(p) prng_type(seed(), n_++));
+ }
+
+ void
+ release(prng_type& p)
+ {
+ std::lock_guard lock(m_);
+ p.next = head_;
+ head_ = &p;
+ }
+
+ static
+ pool&
+ impl()
+ {
+ static pool instance;
+ return instance;
+ }
+ };
+#endif
+};
+
+//------------------------------------------------------------------------------
+
template
-struct stream_base
+struct stream_base : stream_prng
{
// State information for the permessage-deflate extension
struct pmd_type
@@ -165,7 +362,7 @@ struct stream_base
};
template<>
-struct stream_base
+struct stream_base : stream_prng
{
// These stubs are for avoiding linking in the zlib
// code when permessage-deflate is not enabled.
diff --git a/include/boost/beast/websocket/impl/stream.ipp b/include/boost/beast/websocket/impl/stream.ipp
index cf747c23..4aa72995 100644
--- a/include/boost/beast/websocket/impl/stream.ipp
+++ b/include/boost/beast/websocket/impl/stream.ipp
@@ -556,7 +556,7 @@ write_close(DynamicBuffer& db, close_reason const& cr)
if(role_ == role_type::client)
{
fh.mask = true;
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
}
else
{
@@ -608,7 +608,7 @@ write_ping(DynamicBuffer& db,
fh.len = data.size();
fh.mask = role_ == role_type::client;
if(fh.mask)
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::write(db, fh);
if(data.empty())
return;
@@ -641,7 +641,7 @@ build_request(detail::sec_ws_key_type& key,
req.set(http::field::host, host);
req.set(http::field::upgrade, "websocket");
req.set(http::field::connection, "upgrade");
- detail::make_sec_ws_key(key, wr_gen_);
+ detail::make_sec_ws_key(key);
req.set(http::field::sec_websocket_key, key);
req.set(http::field::sec_websocket_version, "13");
build_request_pmd(req, is_deflate_supported{});
diff --git a/include/boost/beast/websocket/impl/write.ipp b/include/boost/beast/websocket/impl/write.ipp
index ee2bc8d4..edaca798 100644
--- a/include/boost/beast/websocket/impl/write.ipp
+++ b/include/boost/beast/websocket/impl/write.ipp
@@ -406,7 +406,7 @@ operator()(
remain_ = buffer_size(cb_);
fh_.fin = fin_;
fh_.len = remain_;
- fh_.key = ws_.wr_gen_();
+ fh_.key = ws_.create_mask();
detail::prepare_key(key_, fh_.key);
ws_.wr_fb_.reset();
detail::write(
@@ -458,7 +458,7 @@ operator()(
n = clamp(remain_, ws_.wr_buf_size_);
remain_ -= n;
fh_.len = n;
- fh_.key = ws_.wr_gen_();
+ fh_.key = ws_.create_mask();
fh_.fin = fin_ ? remain_ == 0 : false;
detail::prepare_key(key_, fh_.key);
buffer_copy(buffer(
@@ -521,7 +521,7 @@ operator()(
}
if(fh_.mask)
{
- fh_.key = ws_.wr_gen_();
+ fh_.key = ws_.create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh_.key);
detail::mask_inplace(b, key);
@@ -666,7 +666,7 @@ write_some(bool fin,
}
if(fh.mask)
{
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh.key);
detail::mask_inplace(b, key);
@@ -740,7 +740,7 @@ write_some(bool fin,
// mask, no autofrag
fh.fin = fin;
fh.len = remain;
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh.key);
detail::fh_buffer fh_buf;
@@ -784,7 +784,7 @@ write_some(bool fin,
ConstBufferSequence> cb{buffers};
for(;;)
{
- fh.key = wr_gen_();
+ fh.key = this->create_mask();
detail::prepared_key key;
detail::prepare_key(key, fh.key);
auto const n = clamp(remain, wr_buf_size_);
diff --git a/include/boost/beast/websocket/stream.hpp b/include/boost/beast/websocket/stream.hpp
index 79c80ef9..315a23d6 100644
--- a/include/boost/beast/websocket/stream.hpp
+++ b/include/boost/beast/websocket/stream.hpp
@@ -206,7 +206,6 @@ class stream
std::size_t wr_buf_opt_ // write buffer size option setting
= 4096;
detail::fh_buffer wr_fb_; // header buffer used for writes
- detail::maskgen wr_gen_; // source of mask keys
detail::pausation paused_rd_; // paused read op
detail::pausation paused_wr_; // paused write op
@@ -633,6 +632,37 @@ public:
return rd_msg_max_;
}
+ /** Set whether the PRNG is cryptographically secure
+
+ This controls whether or not the source of pseudo-random
+ numbers used to produce the masks required by the WebSocket
+ protocol are of cryptographic quality. When the setting is
+ `true`, a strong algorithm is used which cannot be guessed
+ by observing outputs. When the setting is `false`, a much
+ faster algorithm is used.
+ Masking is only performed by streams operating in the client
+ mode. For streams operating in the server mode, this setting
+ has no effect.
+ By default, newly constructed streams use a secure PRNG.
+
+ If the WebSocket stream is used with an encrypted SSL or TLS
+ next layer, if it is known to the application that intermediate
+ proxies are not vulnerable to cache poisoning, or if the
+ application is designed such that an attacker cannot send
+ arbitrary inputs to the stream interface, then the faster
+ algorithm may be used.
+
+ For more information please consult the WebSocket protocol RFC.
+
+ @param value `true` if the PRNG algorithm should be
+ cryptographically secure.
+ */
+ void
+ secure_prng(bool value)
+ {
+ this->secure_prng_ = value;
+ }
+
/** Set the write buffer size option.
Sets the size of the write buffer used by the implementation to
@@ -3563,6 +3593,36 @@ private:
error_code& ec);
};
+/** Manually provide a one-time seed to initialize the PRNG
+
+ This function invokes the specified seed sequence to produce a seed
+ suitable for use with the pseudo-random number generator used to
+ create masks and perform WebSocket protocol handshakes.
+
+ If a seed is not manually provided, the implementation will
+ perform a one-time seed generation using `std::random_device`. This
+ function may be used when the application runs in an environment
+ where the random device is unreliable or does not provide sufficient
+ entropy.
+
+ @par Preconditions
+
+ This function may not be called after any websocket @ref stream objects
+ have been constructed.
+
+ @param ss A reference to a `std::seed_seq` which will be used to seed
+ the pseudo-random number generator. The seed sequence should have at
+ least 256 bits of entropy.
+
+ @see stream::secure_prng
+*/
+inline
+void
+seed_prng(std::seed_seq& ss)
+{
+ detail::stream_prng::seed(&ss);
+}
+
} // websocket
} // beast
} // boost
diff --git a/test/beast/websocket/CMakeLists.txt b/test/beast/websocket/CMakeLists.txt
index a9984897..4a269893 100644
--- a/test/beast/websocket/CMakeLists.txt
+++ b/test/beast/websocket/CMakeLists.txt
@@ -23,7 +23,6 @@ add_executable (tests-beast-websocket
error.cpp
frame.cpp
handshake.cpp
- mask.cpp
option.cpp
ping.cpp
read1.cpp
diff --git a/test/beast/websocket/Jamfile b/test/beast/websocket/Jamfile
index e54d5b84..f4ea4bf9 100644
--- a/test/beast/websocket/Jamfile
+++ b/test/beast/websocket/Jamfile
@@ -13,7 +13,6 @@ local SOURCES =
error.cpp
frame.cpp
handshake.cpp
- mask.cpp
option.cpp
ping.cpp
read1.cpp
diff --git a/test/beast/websocket/mask.cpp b/test/beast/websocket/mask.cpp
deleted file mode 100644
index a4993964..00000000
--- a/test/beast/websocket/mask.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-//
-// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
-//
-// Distributed under the Boost Software License, Version 1.0. (See accompanying
-// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-//
-// Official repository: https://github.com/boostorg/beast
-//
-
-// Test that header file is self-contained.
-#include
-
-#include
-
-namespace boost {
-namespace beast {
-namespace websocket {
-namespace detail {
-
-class mask_test : public beast::unit_test::suite
-{
-public:
- struct test_generator
- {
- using result_type = std::uint32_t;
-
- result_type n = 0;
-
- void
- seed(std::seed_seq const&)
- {
- }
-
- void
- seed(result_type const&)
- {
- }
-
- std::uint32_t
- operator()()
- {
- return n++;
- }
- };
-
- void run() override
- {
- maskgen_t mg;
- BEAST_EXPECT(mg() != 0);
- }
-};
-
-BEAST_DEFINE_TESTSUITE(beast,websocket,mask);
-
-} // detail
-} // websocket
-} // beast
-} // boost
diff --git a/test/beast/websocket/stream.cpp b/test/beast/websocket/stream.cpp
index 2bac48ea..c71a3f44 100644
--- a/test/beast/websocket/stream.cpp
+++ b/test/beast/websocket/stream.cpp
@@ -22,6 +22,11 @@ public:
void
testOptions()
{
+ {
+ std::seed_seq ss{42};
+ seed_prng(ss);
+ }
+
stream ws{ioc_};
ws.auto_fragment(true);
ws.write_buffer_size(2048);
@@ -37,6 +42,9 @@ public:
pass();
}
+ ws.secure_prng(true);
+ ws.secure_prng(false);
+
auto const bad =
[&](permessage_deflate const& pmd)
{