• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5356685938

23 Jun 2023 01:39PM UTC coverage: 91.746% (+0.02%) from 91.728%
5356685938

push

github

randombit
Merge GH #3595 Apply clang-tidy more universally

Previously clang-tidy ruleset disabled certain rules for the cli and
tests. Remove these exceptions, and fix the relevant warnings.

Also fix compile_commands.json which had previously not provided information for
the examples, BoGo shim, or fuzzers. As a result, clang-tidy was effectively
blind to them. Fix various clang-tidy findings in these files.

Additionally fix clang-tidy warnings that were in Boost or Sqlite3 specific
code, which had been accidentally omitted in past checks.

Modify the nightly clang-tidy run to additionally check the examples, fuzzers,
shim, and Sqlite3/Boost specific code.

78183 of 85217 relevant lines covered (91.75%)

12364366.11 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.93
/src/tests/unit_asio_stream.cpp
1
/*
2
* TLS ASIO Stream Unit Tests
3
* (C) 2018-2020 Jack Lloyd
4
*     2018-2020 Hannes Rantzsch, Tim Oesterreich, Rene Meusel
5
*
6
* Botan is released under the Simplified BSD License (see license.txt)
7
*/
8

9
#include "tests.h"
10

11
#if defined(BOTAN_HAS_TLS) && defined(BOTAN_HAS_TLS_ASIO_STREAM)
12

13
   #include <botan/asio_stream.h>
14
   #include <botan/tls_callbacks.h>
15
   #include <botan/tls_session_manager_noop.h>
16

17
   // The boost::beast::test::stream we use is available starting from boost
18
   // version 1.68, so we cannot run these tests with a smaller version.
19
   #include <boost/version.hpp>
20
   #if BOOST_VERSION >= 106800
21

22
      // boost::beast::test::stream's include path has been changed in boost version
23
      // 1.70.
24
      #if BOOST_VERSION < 107000
25
         #include <boost/beast/experimental/test/stream.hpp>
26
      #else
27
         #include <boost/beast/_experimental/test/stream.hpp>
28
      #endif
29

30
      #include <boost/bind.hpp>
31
      #include <utility>
32

33
namespace Botan_Tests {
34

35
namespace net = boost::asio;
36
using error_code = boost::system::error_code;
37

38
constexpr uint8_t TEST_DATA[] =
39
   "The story so far: In the beginning the Universe was created. "
40
   "This has made a lot of people very angry and been widely regarded as a bad move.";
41
constexpr std::size_t TEST_DATA_SIZE = 142;
42
static_assert(sizeof(TEST_DATA) == TEST_DATA_SIZE, "size of TEST_DATA must match TEST_DATA_SIZE");
43

44
/**
45
 * Mocked Botan::TLS::Channel. Pretends to perform TLS operations and triggers appropriate callbacks in StreamCore.
46
 */
47
class MockChannel {
36✔
48
   public:
49
      MockChannel(std::shared_ptr<Botan::TLS::Callbacks> core) :
24✔
50
            m_callbacks(std::move(core)), m_bytes_till_complete_record(TEST_DATA_SIZE), m_active(false) {}
24✔
51

52
   public:
53
      std::size_t received_data(std::span<const uint8_t> data) {
6✔
54
         if(m_bytes_till_complete_record <= data.size()) {
6✔
55
            m_callbacks->tls_record_received(0, TEST_DATA);
6✔
56
            m_active = true;  // claim to be active once a full record has been received (for handshake test)
6✔
57
            return 0;
6✔
58
         }
59
         m_bytes_till_complete_record -= data.size();
×
60
         return m_bytes_till_complete_record;
×
61
      }
62

63
      void send(std::span<const uint8_t> buf) { m_callbacks->tls_emit_data(buf); }
43✔
64

65
      bool is_active() const { return m_active; }
10✔
66

67
   protected:
68
      std::shared_ptr<Botan::TLS::Callbacks> m_callbacks;
69
      std::size_t m_bytes_till_complete_record;  // number of bytes still to read before tls record is completed
70
      bool m_active;
71
};
72

73
class ThrowingMockChannel : public MockChannel {
12✔
74
   public:
75
      static boost::system::error_code expected_ec() { return Botan::TLS::Alert::UnexpectedMessage; }
12✔
76

77
      ThrowingMockChannel(std::shared_ptr<Botan::TLS::Callbacks> core) : MockChannel(std::move(core)) {}
6✔
78

79
      std::size_t received_data(std::span<const uint8_t>) { throw Botan::TLS::Unexpected_Message("test_error"); }
4✔
80

81
      void send(std::span<const uint8_t>) { throw Botan::TLS::Unexpected_Message("test_error"); }
2✔
82
};
83

84
// Unfortunately, boost::beast::test::stream keeps lowest_layer_type private and
85
// only friends boost::asio::ssl::stream. We need to make our own.
86
class TestStream : public boost::beast::test::stream {
25✔
87
   public:
88
      using boost::beast::test::stream::stream;
25✔
89
      using lowest_layer_type = boost::beast::test::stream;
90
};
91

92
using FailCount = boost::beast::test::fail_count;
93

94
class AsioStream : public Botan::TLS::Stream<TestStream, MockChannel> {
95
   public:
96
      template <typename... Args>
97
      AsioStream(std::shared_ptr<Botan::TLS::Context> context, Args&&... args) : Stream(context, args...) {
18✔
98
         m_native_handle = std::make_unique<MockChannel>(m_core);
18✔
99
      }
18✔
100

101
      ~AsioStream() override = default;
×
102
};
103

104
class ThrowingAsioStream : public Botan::TLS::Stream<TestStream, ThrowingMockChannel> {
105
   public:
106
      template <typename... Args>
107
      ThrowingAsioStream(std::shared_ptr<Botan::TLS::Context> context, Args&&... args) : Stream(context, args...) {
6✔
108
         m_native_handle = std::make_unique<ThrowingMockChannel>(m_core);
6✔
109
      }
6✔
110

111
      ~ThrowingAsioStream() override = default;
12✔
112
};
113

114
/**
115
 * Synchronous tests for Botan::Stream.
116
 *
117
 * This test validates the asynchronous behavior Botan::Stream, including its utility classes StreamCore and Async_*_Op.
118
 * The stream's channel, i.e. TLS_Client or TLS_Server, is mocked and pretends to perform TLS operations (noop) and
119
 * provides the test data to the stream.
120
 * The underlying network socket, claiming it read / wrote a number of bytes.
121
 */
122
class Asio_Stream_Tests final : public Test {
×
123
      std::shared_ptr<Botan::TLS::Context> get_context() {
25✔
124
         return std::make_shared<Botan::TLS::Context>(std::make_shared<Botan::Credentials_Manager>(),
50✔
125
                                                      std::make_shared<Botan::Null_RNG>(),
25✔
126
                                                      std::make_shared<Botan::TLS::Session_Manager_Noop>(),
25✔
127
                                                      std::make_shared<Botan::TLS::Default_Policy>());
50✔
128
      }
129

130
      // use memcmp to check if the data in a is a prefix of the data in b
131
      bool contains(const void* a, const void* b, const std::size_t size) { return memcmp(a, b, size) == 0; }
8✔
132

133
      boost::string_view test_data() const {
12✔
134
         return boost::string_view(reinterpret_cast<const char*>(TEST_DATA), TEST_DATA_SIZE);
12✔
135
      }
136

137
      void test_sync_handshake(std::vector<Test::Result>& results) {
1✔
138
         net::io_context ioc;
1✔
139
         auto ctx = get_context();
1✔
140
         AsioStream ssl(ctx, ioc, test_data());
1✔
141

142
         ssl.handshake(Botan::TLS::Connection_Side::Client);
1✔
143

144
         Test::Result result("sync TLS handshake");
1✔
145
         result.test_eq("feeds data into channel until active", ssl.native_handle()->is_active(), true);
1✔
146
         results.push_back(result);
1✔
147
      }
2✔
148

149
      void test_sync_handshake_error(std::vector<Test::Result>& results) {
1✔
150
         net::io_context ioc;
1✔
151
         // fail right away
152
         FailCount fc{0, net::error::no_recovery};
1✔
153
         TestStream remote{ioc};
1✔
154

155
         auto ctx = get_context();
1✔
156
         AsioStream ssl(ctx, ioc, fc);
1✔
157
         ssl.next_layer().connect(remote);
1✔
158

159
         // mimic handshake initialization
160
         ssl.native_handle()->send(TEST_DATA);
1✔
161

162
         error_code ec;
1✔
163
         ssl.handshake(Botan::TLS::Connection_Side::Client, ec);
1✔
164

165
         Test::Result result("sync TLS handshake error");
1✔
166
         result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
1✔
167
         result.confirm("propagates error code", ec == net::error::no_recovery);
3✔
168
         results.push_back(result);
1✔
169
      }
3✔
170

171
      void test_sync_handshake_throw(std::vector<Test::Result>& results) {
1✔
172
         net::io_context ioc;
1✔
173
         TestStream remote{ioc};
1✔
174

175
         auto ctx = get_context();
1✔
176
         ThrowingAsioStream ssl(ctx, ioc, test_data());
1✔
177
         ssl.next_layer().connect(remote);
1✔
178

179
         error_code ec;
1✔
180
         ssl.handshake(Botan::TLS::Connection_Side::Client, ec);
1✔
181

182
         Test::Result result("sync TLS handshake error");
1✔
183
         result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
1✔
184
         result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
3✔
185
         results.push_back(result);
1✔
186
      }
2✔
187

188
      void test_async_handshake(std::vector<Test::Result>& results) {
1✔
189
         net::io_context ioc;
1✔
190
         TestStream remote{ioc};
1✔
191

192
         auto ctx = get_context();
1✔
193
         AsioStream ssl(ctx, ioc, test_data());
1✔
194
         ssl.next_layer().connect(remote);
1✔
195

196
         // mimic handshake initialization
197
         ssl.native_handle()->send(TEST_DATA);
1✔
198

199
         Test::Result result("async TLS handshake");
1✔
200

201
         auto handler = [&](const error_code&) {
2✔
202
            result.confirm("reads from socket", ssl.next_layer().nread() > 0);
2✔
203
            result.confirm("writes from socket", ssl.next_layer().nwrite() > 0);
2✔
204
            result.test_eq("feeds data into channel until active", ssl.native_handle()->is_active(), true);
1✔
205
         };
1✔
206

207
         ssl.async_handshake(Botan::TLS::Connection_Side::Client, handler);
1✔
208

209
         ssl.next_layer().close_remote();
1✔
210
         ioc.run();
1✔
211
         results.push_back(result);
1✔
212
      }
2✔
213

214
      void test_async_handshake_error(std::vector<Test::Result>& results) {
1✔
215
         net::io_context ioc;
1✔
216
         // fail right away
217
         FailCount fc{0, net::error::no_recovery};
1✔
218
         TestStream remote{ioc};
1✔
219

220
         auto ctx = get_context();
1✔
221
         AsioStream ssl(ctx, ioc, fc);
1✔
222
         ssl.next_layer().connect(remote);
1✔
223

224
         // mimic handshake initialization
225
         ssl.native_handle()->send(TEST_DATA);
1✔
226

227
         Test::Result result("async TLS handshake error");
1✔
228

229
         auto handler = [&](const error_code& ec) {
2✔
230
            result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
1✔
231
            result.confirm("propagates error code", ec == net::error::no_recovery);
3✔
232
         };
1✔
233

234
         ssl.async_handshake(Botan::TLS::Connection_Side::Client, handler);
1✔
235

236
         ioc.run();
1✔
237
         results.push_back(result);
1✔
238
      }
2✔
239

240
      void test_async_handshake_throw(std::vector<Test::Result>& results) {
1✔
241
         net::io_context ioc;
1✔
242
         TestStream remote{ioc};
1✔
243

244
         auto ctx = get_context();
1✔
245
         ThrowingAsioStream ssl(ctx, ioc, test_data());
1✔
246
         ssl.next_layer().connect(remote);
1✔
247

248
         Test::Result result("async TLS handshake throw");
1✔
249

250
         auto handler = [&](const error_code& ec) {
2✔
251
            result.test_eq("does not activate channel", ssl.native_handle()->is_active(), false);
1✔
252
            result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
3✔
253
         };
1✔
254

255
         ssl.async_handshake(Botan::TLS::Connection_Side::Client, handler);
1✔
256

257
         ioc.run();
1✔
258
         results.push_back(result);
1✔
259
      }
2✔
260

261
      void test_sync_read_some_success(std::vector<Test::Result>& results) {
1✔
262
         net::io_context ioc;
1✔
263

264
         auto ctx = get_context();
1✔
265
         AsioStream ssl(ctx, ioc, test_data());
1✔
266

267
         const std::size_t buf_size = 128;
1✔
268
         uint8_t buf[buf_size];
1✔
269
         error_code ec;
1✔
270

271
         auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, sizeof(buf)), ec);
1✔
272

273
         Test::Result result("sync read_some success");
1✔
274
         result.confirm("reads the correct data", contains(buf, TEST_DATA, buf_size));
2✔
275
         result.test_eq("reads the correct amount of data", bytes_transferred, buf_size);
1✔
276
         result.confirm("does not report an error", !ec);
2✔
277

278
         results.push_back(result);
1✔
279
      }
2✔
280

281
      void test_sync_read_some_buffer_sequence(std::vector<Test::Result>& results) {
1✔
282
         net::io_context ioc;
1✔
283

284
         auto ctx = get_context();
1✔
285
         AsioStream ssl(ctx, ioc, test_data());
1✔
286
         error_code ec;
1✔
287

288
         std::vector<net::mutable_buffer> data;
1✔
289
         uint8_t buf1[TEST_DATA_SIZE / 2];
1✔
290
         uint8_t buf2[TEST_DATA_SIZE / 2];
1✔
291
         data.emplace_back(net::mutable_buffer(buf1, TEST_DATA_SIZE / 2));
1✔
292
         data.emplace_back(net::mutable_buffer(buf2, TEST_DATA_SIZE / 2));
1✔
293

294
         auto bytes_transferred = net::read(ssl, data, ec);
1✔
295

296
         Test::Result result("sync read_some buffer sequence");
1✔
297

298
         result.confirm("reads the correct data",
2✔
299
                        contains(buf1, TEST_DATA, TEST_DATA_SIZE / 2) &&
1✔
300
                           contains(buf2, TEST_DATA + TEST_DATA_SIZE / 2, TEST_DATA_SIZE / 2));
1✔
301
         result.test_eq("reads the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
1✔
302
         result.confirm("does not report an error", !ec);
2✔
303

304
         results.push_back(result);
1✔
305
      }
3✔
306

307
      void test_sync_read_some_error(std::vector<Test::Result>& results) {
1✔
308
         net::io_context ioc;
1✔
309
         // fail right away
310
         FailCount fc{0, net::error::no_recovery};
1✔
311
         TestStream remote{ioc};
1✔
312

313
         auto ctx = get_context();
1✔
314
         AsioStream ssl(ctx, ioc, fc);
1✔
315
         ssl.next_layer().connect(remote);
1✔
316

317
         uint8_t buf[128];
1✔
318
         error_code ec;
1✔
319

320
         auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, sizeof(buf)), ec);
1✔
321

322
         Test::Result result("sync read_some error");
1✔
323
         result.test_eq("didn't transfer anything", bytes_transferred, 0);
1✔
324
         result.confirm("propagates error code", ec == net::error::no_recovery);
3✔
325

326
         results.push_back(result);
1✔
327
      }
2✔
328

329
      void test_sync_read_some_throw(std::vector<Test::Result>& results) {
1✔
330
         net::io_context ioc;
1✔
331
         TestStream remote{ioc};
1✔
332

333
         auto ctx = get_context();
1✔
334
         ThrowingAsioStream ssl(ctx, ioc, test_data());
1✔
335
         ssl.next_layer().connect(remote);
1✔
336

337
         uint8_t buf[128];
1✔
338
         error_code ec;
1✔
339

340
         auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, sizeof(buf)), ec);
1✔
341

342
         Test::Result result("sync read_some throw");
1✔
343
         result.test_eq("didn't transfer anything", bytes_transferred, 0);
1✔
344
         result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
3✔
345

346
         results.push_back(result);
1✔
347
      }
2✔
348

349
      void test_sync_read_zero_buffer(std::vector<Test::Result>& results) {
1✔
350
         net::io_context ioc;
1✔
351

352
         auto ctx = get_context();
1✔
353
         AsioStream ssl(ctx, ioc);
1✔
354

355
         const std::size_t buf_size = 128;
1✔
356
         uint8_t buf[buf_size];
1✔
357
         error_code ec;
1✔
358

359
         auto bytes_transferred = net::read(ssl, net::mutable_buffer(buf, std::size_t(0)), ec);
1✔
360

361
         Test::Result result("sync read_some into zero-size buffer");
1✔
362
         result.test_eq("reads the correct amount of data", bytes_transferred, 0);
1✔
363
         // This relies on an implementation detail of TestStream: A "real" asio::tcp::stream
364
         // would block here. TestStream sets error_code::eof.
365
         result.confirm("does not report an error", !ec);
2✔
366

367
         results.push_back(result);
1✔
368
      }
2✔
369

370
      void test_async_read_some_success(std::vector<Test::Result>& results) {
1✔
371
         net::io_context ioc;
1✔
372
         TestStream remote{ioc};
1✔
373

374
         auto ctx = get_context();
1✔
375
         AsioStream ssl(ctx, ioc, test_data());
1✔
376
         uint8_t data[TEST_DATA_SIZE];
1✔
377

378
         Test::Result result("async read_some success");
1✔
379

380
         auto read_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
381
            result.confirm("reads the correct data", contains(data, TEST_DATA, TEST_DATA_SIZE));
2✔
382
            result.test_eq("reads the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
1✔
383
            result.confirm("does not report an error", !ec);
2✔
384
         };
1✔
385

386
         net::mutable_buffer buf{data, TEST_DATA_SIZE};
1✔
387
         net::async_read(ssl, buf, read_handler);
1✔
388

389
         ssl.next_layer().close_remote();
1✔
390
         ioc.run();
1✔
391
         results.push_back(result);
1✔
392
      }
2✔
393

394
      void test_async_read_some_buffer_sequence(std::vector<Test::Result>& results) {
1✔
395
         net::io_context ioc;
1✔
396
         auto ctx = get_context();
1✔
397
         AsioStream ssl(ctx, ioc, test_data());
1✔
398

399
         std::vector<net::mutable_buffer> data;
1✔
400
         uint8_t buf1[TEST_DATA_SIZE / 2];
1✔
401
         uint8_t buf2[TEST_DATA_SIZE / 2];
1✔
402
         data.emplace_back(net::mutable_buffer(buf1, TEST_DATA_SIZE / 2));
1✔
403
         data.emplace_back(net::mutable_buffer(buf2, TEST_DATA_SIZE / 2));
1✔
404

405
         Test::Result result("async read_some buffer sequence");
1✔
406

407
         auto read_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
408
            result.confirm("reads the correct data",
2✔
409
                           contains(buf1, TEST_DATA, TEST_DATA_SIZE / 2) &&
1✔
410
                              contains(buf2, TEST_DATA + TEST_DATA_SIZE / 2, TEST_DATA_SIZE / 2));
1✔
411
            result.test_eq("reads the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
1✔
412
            result.confirm("does not report an error", !ec);
2✔
413
         };
1✔
414

415
         net::async_read(ssl, data, read_handler);
1✔
416

417
         ssl.next_layer().close_remote();
1✔
418
         ioc.run();
1✔
419
         results.push_back(result);
1✔
420
      }
3✔
421

422
      void test_async_read_some_error(std::vector<Test::Result>& results) {
1✔
423
         net::io_context ioc;
1✔
424
         // fail right away
425
         FailCount fc{0, net::error::no_recovery};
1✔
426
         auto ctx = get_context();
1✔
427
         AsioStream ssl(ctx, ioc, fc);
1✔
428
         uint8_t data[TEST_DATA_SIZE];
1✔
429

430
         Test::Result result("async read_some error");
1✔
431

432
         auto read_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
433
            result.test_eq("didn't transfer anything", bytes_transferred, 0);
1✔
434
            result.confirm("propagates error code", ec == net::error::no_recovery);
3✔
435
         };
1✔
436

437
         net::mutable_buffer buf{data, TEST_DATA_SIZE};
1✔
438
         net::async_read(ssl, buf, read_handler);
1✔
439

440
         ssl.next_layer().close_remote();
1✔
441
         ioc.run();
1✔
442
         results.push_back(result);
1✔
443
      }
2✔
444

445
      void test_async_read_some_throw(std::vector<Test::Result>& results) {
1✔
446
         net::io_context ioc;
1✔
447
         auto ctx = get_context();
1✔
448
         ThrowingAsioStream ssl(ctx, ioc, test_data());
1✔
449
         uint8_t data[TEST_DATA_SIZE];
1✔
450

451
         Test::Result result("async read_some throw");
1✔
452

453
         auto read_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
454
            result.test_eq("didn't transfer anything", bytes_transferred, 0);
1✔
455
            result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
3✔
456
         };
1✔
457

458
         net::mutable_buffer buf{data, TEST_DATA_SIZE};
1✔
459
         net::async_read(ssl, buf, read_handler);
1✔
460

461
         ssl.next_layer().close_remote();
1✔
462
         ioc.run();
1✔
463
         results.push_back(result);
1✔
464
      }
2✔
465

466
      void test_async_read_zero_buffer(std::vector<Test::Result>& results) {
1✔
467
         net::io_context ioc;
1✔
468
         TestStream remote{ioc};
1✔
469

470
         auto ctx = get_context();
1✔
471
         AsioStream ssl(ctx, ioc);
1✔
472
         uint8_t data[TEST_DATA_SIZE];
1✔
473

474
         Test::Result result("async read_some into zero-size buffer");
1✔
475

476
         auto read_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
477
            result.test_eq("reads the correct amount of data", bytes_transferred, 0);
1✔
478
            // This relies on an implementation detail of TestStream: A "real" asio::tcp::stream
479
            // would block here. TestStream sets error_code::eof.
480
            result.confirm("does not report an error", !ec);
2✔
481
         };
1✔
482

483
         net::mutable_buffer buf{data, std::size_t(0)};
1✔
484
         net::async_read(ssl, buf, read_handler);
1✔
485

486
         ssl.next_layer().close_remote();
1✔
487
         ioc.run();
1✔
488
         results.push_back(result);
1✔
489
      }
2✔
490

491
      void test_sync_write_some_success(std::vector<Test::Result>& results) {
1✔
492
         net::io_context ioc;
1✔
493
         TestStream remote{ioc};
1✔
494

495
         auto ctx = get_context();
1✔
496
         AsioStream ssl(ctx, ioc);
1✔
497
         ssl.next_layer().connect(remote);
1✔
498
         error_code ec;
1✔
499

500
         auto bytes_transferred = net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
1✔
501

502
         Test::Result result("sync write_some success");
1✔
503
         result.confirm("writes the correct data", remote.str() == test_data());
3✔
504
         result.test_eq("writes the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
1✔
505
         result.confirm("does not report an error", !ec);
2✔
506

507
         results.push_back(result);
1✔
508
      }
2✔
509

510
      void test_sync_no_handshake(std::vector<Test::Result>& results) {
1✔
511
         net::io_context ioc;
1✔
512
         TestStream remote{ioc};
1✔
513

514
         auto ctx = get_context();
1✔
515
         Botan::TLS::Stream<TestStream> ssl(ctx, ioc);  // Note that we're not using MockChannel here
1✔
516
         ssl.next_layer().connect(remote);
1✔
517
         error_code ec;
1✔
518

519
         net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
1✔
520

521
         Test::Result result("sync write_some without handshake fails gracefully");
1✔
522
         result.confirm("reports an error", ec.failed());
2✔
523

524
         results.push_back(result);
1✔
525
      }
2✔
526

527
      void test_sync_write_some_buffer_sequence(std::vector<Test::Result>& results) {
1✔
528
         net::io_context ioc;
1✔
529
         TestStream remote{ioc};
1✔
530

531
         auto ctx = get_context();
1✔
532
         AsioStream ssl(ctx, ioc);
1✔
533
         ssl.next_layer().connect(remote);
1✔
534
         error_code ec;
1✔
535

536
         // this should be Botan::TLS::MAX_PLAINTEXT_SIZE + 1024 + 1
537
         std::array<uint8_t, 17 * 1024 + 1> random_data;
1✔
538
         random_data.fill('4');  // chosen by fair dice roll
1✔
539
         random_data.back() = '5';
1✔
540

541
         std::vector<net::const_buffer> data;
1✔
542
         data.emplace_back(net::const_buffer(random_data.data(), 1));
1✔
543
         for(std::size_t i = 1; i < random_data.size(); i += 1024) {
18✔
544
            data.emplace_back(net::const_buffer(random_data.data() + i, 1024));
17✔
545
         }
546

547
         auto bytes_transferred = net::write(ssl, data, ec);
1✔
548

549
         Test::Result result("sync write_some buffer sequence");
1✔
550

551
         result.confirm("[precondition] MAX_PLAINTEXT_SIZE is still smaller than random_data.size()",
2✔
552
                        Botan::TLS::MAX_PLAINTEXT_SIZE < random_data.size());
553

554
         result.confirm("writes the correct data",
2✔
555
                        contains(remote.buffer().data().data(), random_data.data(), random_data.size()));
1✔
556
         result.test_eq("writes the correct amount of data", bytes_transferred, random_data.size());
1✔
557
         result.test_eq("correct number of writes", ssl.next_layer().nwrite(), 2);
1✔
558
         result.confirm("does not report an error", !ec);
2✔
559

560
         results.push_back(result);
1✔
561
      }
3✔
562

563
      void test_sync_write_some_error(std::vector<Test::Result>& results) {
1✔
564
         net::io_context ioc;
1✔
565
         // fail right away
566
         FailCount fc{0, net::error::no_recovery};
1✔
567
         TestStream remote{ioc};
1✔
568

569
         auto ctx = get_context();
1✔
570
         AsioStream ssl(ctx, ioc, fc);
1✔
571
         ssl.next_layer().connect(remote);
1✔
572

573
         error_code ec;
1✔
574

575
         auto bytes_transferred = net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
1✔
576

577
         Test::Result result("sync write_some error");
1✔
578
         result.test_eq("didn't transfer anything", bytes_transferred, 0);
1✔
579
         result.confirm("propagates error code", ec == net::error::no_recovery);
3✔
580

581
         results.push_back(result);
1✔
582
      }
2✔
583

584
      void test_sync_write_some_throw(std::vector<Test::Result>& results) {
1✔
585
         net::io_context ioc;
1✔
586
         TestStream remote{ioc};
1✔
587

588
         auto ctx = get_context();
1✔
589
         ThrowingAsioStream ssl(ctx, ioc);
1✔
590
         ssl.next_layer().connect(remote);
1✔
591
         error_code ec;
1✔
592

593
         auto bytes_transferred = net::write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), ec);
1✔
594

595
         Test::Result result("sync write_some throw");
1✔
596
         result.test_eq("didn't transfer anything", bytes_transferred, 0);
1✔
597
         result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
3✔
598

599
         results.push_back(result);
1✔
600
      }
2✔
601

602
      void test_async_write_some_success(std::vector<Test::Result>& results) {
1✔
603
         net::io_context ioc;
1✔
604
         TestStream remote{ioc};
1✔
605

606
         auto ctx = get_context();
1✔
607
         AsioStream ssl(ctx, ioc);
1✔
608
         ssl.next_layer().connect(remote);
1✔
609

610
         Test::Result result("async write_some success");
1✔
611

612
         auto write_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
613
            result.confirm("writes the correct data", remote.str() == test_data());
3✔
614
            result.test_eq("writes the correct amount of data", bytes_transferred, TEST_DATA_SIZE);
1✔
615
            result.confirm("does not report an error", !ec);
2✔
616
         };
1✔
617

618
         net::async_write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), write_handler);
1✔
619

620
         ioc.run();
1✔
621
         results.push_back(result);
1✔
622
      }
2✔
623

624
      void test_async_write_some_buffer_sequence(std::vector<Test::Result>& results) {
1✔
625
         net::io_context ioc;
1✔
626
         TestStream remote{ioc};
1✔
627

628
         auto ctx = get_context();
1✔
629
         AsioStream ssl(ctx, ioc);
1✔
630
         ssl.next_layer().connect(remote);
1✔
631

632
         // this should be Botan::TLS::MAX_PLAINTEXT_SIZE + 1024 + 1
633
         std::array<uint8_t, 17 * 1024 + 1> random_data;
1✔
634
         random_data.fill('4');  // chosen by fair dice roll
1✔
635
         random_data.back() = '5';
1✔
636

637
         std::vector<net::const_buffer> src;
1✔
638
         src.emplace_back(net::const_buffer(random_data.data(), 1));
1✔
639
         for(std::size_t i = 1; i < random_data.size(); i += 1024) {
18✔
640
            src.emplace_back(net::const_buffer(random_data.data() + i, 1024));
17✔
641
         }
642

643
         Test::Result result("async write_some buffer sequence");
1✔
644

645
         result.confirm("[precondition] MAX_PLAINTEXT_SIZE is still smaller than random_data.size()",
2✔
646
                        Botan::TLS::MAX_PLAINTEXT_SIZE < random_data.size());
647

648
         auto write_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
649
            result.confirm("writes the correct data",
2✔
650
                           contains(remote.buffer().data().data(), random_data.data(), random_data.size()));
1✔
651
            result.test_eq("writes the correct amount of data", bytes_transferred, random_data.size());
1✔
652
            result.test_eq("correct number of writes", ssl.next_layer().nwrite(), 2);
1✔
653
            result.confirm("does not report an error", !ec);
2✔
654
         };
1✔
655

656
         net::async_write(ssl, src, write_handler);
1✔
657

658
         ioc.run();
1✔
659
         results.push_back(result);
1✔
660
      }
3✔
661

662
      void test_async_write_some_error(std::vector<Test::Result>& results) {
1✔
663
         net::io_context ioc;
1✔
664
         // fail right away
665
         FailCount fc{0, net::error::no_recovery};
1✔
666
         TestStream remote{ioc};
1✔
667

668
         auto ctx = get_context();
1✔
669
         AsioStream ssl(ctx, ioc, fc);
1✔
670
         ssl.next_layer().connect(remote);
1✔
671

672
         Test::Result result("async write_some error");
1✔
673

674
         auto write_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
675
            result.test_eq("committed some bytes to the core", bytes_transferred, TEST_DATA_SIZE);
1✔
676
            result.confirm("propagates error code", ec == net::error::no_recovery);
3✔
677
         };
1✔
678

679
         net::async_write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), write_handler);
1✔
680

681
         ioc.run();
1✔
682
         results.push_back(result);
1✔
683
      }
2✔
684

685
      void test_async_write_throw(std::vector<Test::Result>& results) {
1✔
686
         net::io_context ioc;
1✔
687
         TestStream remote{ioc};
1✔
688

689
         auto ctx = get_context();
1✔
690
         ThrowingAsioStream ssl(ctx, ioc);
1✔
691
         ssl.next_layer().connect(remote);
1✔
692

693
         Test::Result result("async write_some throw");
1✔
694

695
         auto write_handler = [&](const error_code& ec, std::size_t bytes_transferred) {
2✔
696
            result.test_eq("didn't transfer anything", bytes_transferred, 0);
1✔
697
            result.confirm("propagates error code", ec == ThrowingMockChannel::expected_ec());
3✔
698
         };
1✔
699

700
         net::async_write(ssl, net::const_buffer(TEST_DATA, TEST_DATA_SIZE), write_handler);
1✔
701

702
         ioc.run();
1✔
703
         results.push_back(result);
1✔
704
      }
2✔
705

706
   public:
707
      std::vector<Test::Result> run() override {
1✔
708
         std::vector<Test::Result> results;
1✔
709

710
         test_sync_no_handshake(results);
1✔
711

712
         test_sync_handshake(results);
1✔
713
         test_sync_handshake_error(results);
1✔
714
         test_sync_handshake_throw(results);
1✔
715

716
         test_async_handshake(results);
1✔
717
         test_async_handshake_error(results);
1✔
718
         test_async_handshake_throw(results);
1✔
719

720
         test_sync_read_some_success(results);
1✔
721
         test_sync_read_some_buffer_sequence(results);
1✔
722
         test_sync_read_some_error(results);
1✔
723
         test_sync_read_some_throw(results);
1✔
724
         test_sync_read_zero_buffer(results);
1✔
725

726
         test_async_read_some_success(results);
1✔
727
         test_async_read_some_buffer_sequence(results);
1✔
728
         test_async_read_some_error(results);
1✔
729
         test_async_read_some_throw(results);
1✔
730
         test_async_read_zero_buffer(results);
1✔
731

732
         test_sync_write_some_success(results);
1✔
733
         test_sync_write_some_buffer_sequence(results);
1✔
734
         test_sync_write_some_error(results);
1✔
735
         test_sync_write_some_throw(results);
1✔
736

737
         test_async_write_some_success(results);
1✔
738
         test_async_write_some_buffer_sequence(results);
1✔
739
         test_async_write_some_error(results);
1✔
740
         test_async_write_throw(results);
1✔
741

742
         return results;
1✔
743
      }
×
744
};
745

746
BOTAN_REGISTER_TEST("tls", "tls_asio_stream", Asio_Stream_Tests);
747

748
}  // namespace Botan_Tests
749

750
   #endif  // BOOST_VERSION
751
#endif     // BOTAN_HAS_TLS && BOTAN_HAS_BOOST_ASIO
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc