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

realm / realm-core / 2309

10 May 2024 05:50PM UTC coverage: 90.809% (+0.009%) from 90.8%
2309

push

Evergreen

danieltabacaru
Add back ability to format Objective-C code

102086 of 181070 branches covered (56.38%)

214553 of 236269 relevant lines covered (90.81%)

5697616.18 hits per line

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

89.59
/test/test_util_network_ssl.cpp
1
#include <thread>
2

3
#include <realm/sync/network/network_ssl.hpp>
4
#include <realm/util/future.hpp>
5

6
#include "test.hpp"
7
#include "util/semaphore.hpp"
8

9
using namespace realm;
10
using namespace realm::sync;
11
using namespace realm::test_util;
12
using namespace realm::util;
13

14
// Test independence and thread-safety
15
// -----------------------------------
16
//
17
// All tests must be thread safe and independent of each other. This
18
// is required because it allows for both shuffling of the execution
19
// order and for parallelized testing.
20
//
21
// In particular, avoid using std::rand() since it is not guaranteed
22
// to be thread safe. Instead use the API offered in
23
// `test/util/random.hpp`.
24
//
25
// All files created in tests must use the TEST_PATH macro (or one of
26
// its friends) to obtain a suitable file system path. See
27
// `test/util/test_path.hpp`.
28
//
29
//
30
// Debugging and the ONLY() macro
31
// ------------------------------
32
//
33
// A simple way of disabling all tests except one called `Foo`, is to
34
// replace TEST(Foo) with ONLY(Foo) and then recompile and rerun the
35
// test suite. Note that you can also use filtering by setting the
36
// environment varible `UNITTEST_FILTER`. See `README.md` for more on
37
// this.
38
//
39
// Another way to debug a particular test, is to copy that test into
40
// `experiments/testcase.cpp` and then run `sh build.sh
41
// check-testcase` (or one of its friends) from the command line.
42

43
#if !REALM_MOBILE
44
namespace {
45

46
network::Endpoint bind_acceptor(network::Acceptor& acceptor)
47
{
41✔
48
    network::Endpoint ep; // Wildcard
41✔
49
    acceptor.open(ep.protocol());
41✔
50
    acceptor.bind(ep);
41✔
51
    ep = acceptor.local_endpoint(); // Get actual bound endpoint
41✔
52
    acceptor.listen();
41✔
53
    return ep;
41✔
54
}
41✔
55

56
void connect_sockets(network::Socket& server_socket, network::Socket& client_socket)
57
{
41✔
58
    network::Service& server_service = server_socket.get_service();
41✔
59
    network::Service& client_service = client_socket.get_service();
41✔
60
    network::Acceptor acceptor(server_service);
41✔
61
    network::Endpoint ep = bind_acceptor(acceptor);
41✔
62
    bool accept_occurred = false, connect_occurred = false;
41✔
63
    auto accept_handler = [&](std::error_code ec) {
41✔
64
        REALM_ASSERT(!ec);
41✔
65
        accept_occurred = true;
41✔
66
    };
41✔
67
    auto connect_handler = [&](std::error_code ec) {
41✔
68
        REALM_ASSERT(!ec);
41✔
69
        connect_occurred = true;
41✔
70
    };
41✔
71
    server_service.post([&](Status status) {
41✔
72
        if (!status.is_ok())
41✔
73
            return;
×
74
        acceptor.async_accept(server_socket, std::move(accept_handler));
41✔
75
    });
41✔
76
    client_service.post([&](Status status) {
41✔
77
        if (!status.is_ok())
41✔
78
            return;
×
79
        client_socket.async_connect(ep, std::move(connect_handler));
41✔
80
    });
41✔
81
    if (&server_service == &client_service) {
41✔
82
        server_service.run();
20✔
83
    }
20✔
84
    else {
21✔
85
        std::thread thread{[&] {
21✔
86
            server_service.run();
21✔
87
        }};
21✔
88
        client_service.run();
21✔
89
        thread.join();
21✔
90
    }
21✔
91
    REALM_ASSERT(accept_occurred);
41✔
92
    REALM_ASSERT(connect_occurred);
41✔
93
}
41✔
94

95
void configure_server_ssl_context_for_test(network::ssl::Context& ssl_context)
96
{
32✔
97
    ssl_context.use_certificate_chain_file(get_test_resource_path() + "test_util_network_ssl_ca.pem");
32✔
98
    ssl_context.use_private_key_file(get_test_resource_path() + "test_util_network_ssl_key.pem");
32✔
99
}
32✔
100

101
void connect_ssl_streams(network::ssl::Stream& server_stream, network::ssl::Stream& client_stream)
102
{
24✔
103
    network::Socket& server_socket = server_stream.lowest_layer();
24✔
104
    network::Socket& client_socket = client_stream.lowest_layer();
24✔
105
    connect_sockets(server_socket, client_socket);
24✔
106
    network::Service& server_service = server_socket.get_service();
24✔
107
    network::Service& client_service = client_socket.get_service();
24✔
108
    bool server_handshake_occurred = false, client_handshake_occurred = false;
24✔
109
    auto server_handshake_handler = [&](std::error_code ec) {
24✔
110
        REALM_ASSERT(!ec);
24✔
111
        server_handshake_occurred = true;
24✔
112
    };
24✔
113
    auto client_handshake_handler = [&](std::error_code ec) {
24✔
114
        REALM_ASSERT(!ec);
24✔
115
        client_handshake_occurred = true;
24✔
116
    };
24✔
117
    server_service.post([&](Status status) {
24✔
118
        if (!status.is_ok())
24✔
119
            return;
×
120
        server_stream.async_handshake(std::move(server_handshake_handler));
24✔
121
    });
24✔
122
    client_service.post([&](Status status) {
24✔
123
        if (!status.is_ok())
24✔
124
            return;
×
125
        client_stream.async_handshake(std::move(client_handshake_handler));
24✔
126
    });
24✔
127
    if (&server_service == &client_service) {
24✔
128
        server_service.run();
16✔
129
    }
16✔
130
    else {
8✔
131
        std::thread thread{[&] {
8✔
132
            server_service.run();
8✔
133
        }};
8✔
134
        client_service.run();
8✔
135
        thread.join();
8✔
136
    }
8✔
137
    REALM_ASSERT(server_handshake_occurred);
24✔
138
    REALM_ASSERT(client_handshake_occurred);
24✔
139
}
24✔
140

141

142
class PingPongDelayFixture {
143
public:
144
    PingPongDelayFixture(network::Service& service)
145
        : PingPongDelayFixture{service, service}
146
    {
×
147
    }
×
148

149
    PingPongDelayFixture(network::Service& server_service, network::Service& client_service)
150
        : m_server_socket{server_service}
151
        , m_client_socket{client_service}
152
    {
×
153
        connect_sockets(m_server_socket, m_client_socket);
×
154
    }
×
155

156
    // Must be called by thread associated with `server_service`
157
    void start_server()
158
    {
×
159
        initiate_server_read();
×
160
    }
×
161

162
    // Must be called by thread associated with `server_service`
163
    void stop_server()
164
    {
×
165
        m_server_socket.cancel();
×
166
    }
×
167

168
    // Must be called by thread associated with `client_service`
169
    void delay_client(UniqueFunction<void()> handler, int n = 512)
170
    {
×
171
        m_handler = std::move(handler);
×
172
        m_num = n;
×
173
        initiate_client_write();
×
174
    }
×
175

176
private:
177
    network::Socket m_server_socket, m_client_socket;
178
    char m_server_char = 0, m_client_char = 0;
179
    int m_num;
180
    UniqueFunction<void()> m_handler;
181

182
    void initiate_server_read()
183
    {
×
184
        auto handler = [this](std::error_code ec, size_t) {
×
185
            if (ec != error::operation_aborted)
×
186
                handle_server_read(ec);
×
187
        };
×
188
        m_server_socket.async_read(&m_server_char, 1, std::move(handler));
×
189
    }
×
190

191
    void handle_server_read(std::error_code ec)
192
    {
×
193
        if (ec)
×
194
            throw std::system_error(ec);
×
195
        initiate_server_write();
×
196
    }
×
197

198
    void initiate_server_write()
199
    {
×
200
        auto handler = [this](std::error_code ec, size_t) {
×
201
            if (ec != error::operation_aborted)
×
202
                handle_server_write(ec);
×
203
        };
×
204
        m_server_socket.async_write(&m_server_char, 1, std::move(handler));
×
205
    }
×
206

207
    void handle_server_write(std::error_code ec)
208
    {
×
209
        if (ec)
×
210
            throw std::system_error(ec);
×
211
        initiate_server_read();
×
212
    }
×
213

214
    void initiate_client_write()
215
    {
×
216
        if (m_num <= 0) {
×
217
            UniqueFunction<void()> handler = std::move(m_handler);
×
218
            m_handler = nullptr;
×
219
            handler();
×
220
            return;
×
221
        }
×
222
        --m_num;
×
223

×
224
        auto handler = [this](std::error_code ec, size_t) {
×
225
            if (ec != error::operation_aborted)
×
226
                handle_client_write(ec);
×
227
        };
×
228
        m_client_socket.async_write(&m_client_char, 1, std::move(handler));
×
229
    }
×
230

231
    void handle_client_write(std::error_code ec)
232
    {
×
233
        if (ec)
×
234
            throw std::system_error(ec);
×
235
        initiate_client_read();
×
236
    }
×
237

238
    void initiate_client_read()
239
    {
×
240
        auto handler = [this](std::error_code ec, size_t) {
×
241
            if (ec != error::operation_aborted)
×
242
                handle_client_read(ec);
×
243
        };
×
244
        m_client_socket.async_read(&m_client_char, 1, std::move(handler));
×
245
    }
×
246

247
    void handle_client_read(std::error_code ec)
248
    {
×
249
        if (ec)
×
250
            throw std::system_error(ec);
×
251
        initiate_client_write();
×
252
    }
×
253
};
254

255
} // unnamed namespace
256

257

258
TEST(Util_Network_SSL_Handshake)
259
{
2✔
260
    network::Service service_1, service_2;
2✔
261
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
262
    network::ssl::Context ssl_context_1;
2✔
263
    network::ssl::Context ssl_context_2;
2✔
264
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
265
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
266
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
267
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
268
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
269
    connect_sockets(socket_1, socket_2);
2✔
270

271
    auto connector = [&] {
2✔
272
        std::error_code ec;
2✔
273
        ssl_stream_2.handshake(ec);
2✔
274
        CHECK_EQUAL(std::error_code(), ec);
2✔
275
    };
2✔
276
    auto acceptor = [&] {
2✔
277
        std::error_code ec;
2✔
278
        ssl_stream_1.handshake(ec);
2✔
279
        CHECK_EQUAL(std::error_code(), ec);
2✔
280
    };
2✔
281

282
    std::thread thread_1(std::move(connector));
2✔
283
    std::thread thread_2(std::move(acceptor));
2✔
284
    thread_1.join();
2✔
285
    thread_2.join();
2✔
286
}
2✔
287

288

289
TEST(Util_Network_SSL_AsyncHandshake)
290
{
2✔
291
    network::Service service;
2✔
292
    network::Socket socket_1{service}, socket_2{service};
2✔
293
    network::ssl::Context ssl_context_1;
2✔
294
    network::ssl::Context ssl_context_2;
2✔
295
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
296
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
297
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
298
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
299
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
300
    connect_sockets(socket_1, socket_2);
2✔
301

302
    bool connect_completed = false;
2✔
303
    auto connect_handler = [&](std::error_code ec) {
2✔
304
        CHECK_EQUAL(std::error_code(), ec);
2✔
305
        connect_completed = true;
2✔
306
    };
2✔
307
    bool accept_completed = false;
2✔
308
    auto accept_handler = [&](std::error_code ec) {
2✔
309
        CHECK_EQUAL(std::error_code(), ec);
2✔
310
        accept_completed = true;
2✔
311
    };
2✔
312

313
    ssl_stream_1.async_handshake(std::move(accept_handler));
2✔
314
    ssl_stream_2.async_handshake(std::move(connect_handler));
2✔
315
    service.run();
2✔
316
    CHECK(connect_completed);
2✔
317
    CHECK(accept_completed);
2✔
318
}
2✔
319

320

321
TEST(Util_Network_SSL_ReadWriteShutdown)
322
{
2✔
323
    network::Service service_1, service_2;
2✔
324
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
325
    network::ssl::Context ssl_context_1;
2✔
326
    network::ssl::Context ssl_context_2;
2✔
327
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
328
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
329
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
330
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
331
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
332
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
333

334
    const char* message = "hello";
2✔
335
    char buffer[256];
2✔
336

337
    auto writer = [&] {
2✔
338
        std::size_t n = ssl_stream_1.write(message, std::strlen(message));
2✔
339
        CHECK_EQUAL(std::strlen(message), n);
2✔
340
        ssl_stream_1.shutdown();
2✔
341
    };
2✔
342
    auto reader = [&] {
2✔
343
        std::error_code ec;
2✔
344
        std::size_t n = ssl_stream_2.read(buffer, sizeof buffer, ec);
2✔
345
        if (CHECK_EQUAL(MiscExtErrors::end_of_input, ec)) {
2✔
346
            if (CHECK_EQUAL(std::strlen(message), n))
2✔
347
                CHECK(std::equal(buffer, buffer + n, message));
2✔
348
        }
2✔
349
    };
2✔
350

351
    std::thread thread_1(std::move(writer));
2✔
352
    std::thread thread_2(std::move(reader));
2✔
353
    thread_1.join();
2✔
354
    thread_2.join();
2✔
355
}
2✔
356

357

358
TEST(Util_Network_SSL_AsyncReadWriteShutdown)
359
{
2✔
360
    network::Service service;
2✔
361
    network::Socket socket_1{service}, socket_2{service};
2✔
362
    network::ssl::Context ssl_context_1;
2✔
363
    network::ssl::Context ssl_context_2;
2✔
364
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
365
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
366
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
367
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
368
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
369
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
370

371
    const char* message = "hello";
2✔
372
    char buffer[256];
2✔
373

374
    bool shutdown_completed = false;
2✔
375
    auto shutdown_handler = [&](std::error_code ec) {
2✔
376
        CHECK_EQUAL(std::error_code(), ec);
2✔
377
        shutdown_completed = true;
2✔
378
    };
2✔
379
    auto write_handler = [&](std::error_code ec, std::size_t n) {
2✔
380
        CHECK_EQUAL(std::error_code(), ec);
2✔
381
        CHECK_EQUAL(std::strlen(message), n);
2✔
382
        ssl_stream_1.async_shutdown(std::move(shutdown_handler));
2✔
383
    };
2✔
384
    bool read_completed = false;
2✔
385
    auto read_handler = [&](std::error_code ec, std::size_t n) {
2✔
386
        CHECK_EQUAL(MiscExtErrors::end_of_input, ec);
2✔
387
        if (CHECK_EQUAL(std::strlen(message), n))
2✔
388
            CHECK(std::equal(buffer, buffer + n, message));
2✔
389
        read_completed = true;
2✔
390
    };
2✔
391

392
    ssl_stream_1.async_write(message, std::strlen(message), std::move(write_handler));
2✔
393
    ssl_stream_2.async_read(buffer, sizeof buffer, std::move(read_handler));
2✔
394
    service.run();
2✔
395
    CHECK(shutdown_completed);
2✔
396
    CHECK(read_completed);
2✔
397
}
2✔
398

399

400
TEST(Util_Network_SSL_PrematureEndOfInputOnHandshakeRead)
401
{
2✔
402
    network::Service service_1, service_2;
2✔
403
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
404
    network::ssl::Context ssl_context_1;
2✔
405
    network::ssl::Context ssl_context_2;
2✔
406
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
407
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
408
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
409
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
410
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
411
    connect_sockets(socket_1, socket_2);
2✔
412

413
    socket_1.shutdown(network::Socket::shutdown_send);
2✔
414

415
    // Use a separate thread to consume data written by Stream::handshake(),
416
    // such that we can be sure not to block.
417
    auto consumer = [&] {
2✔
418
        constexpr std::size_t size = 4096;
2✔
419
        std::unique_ptr<char[]> buffer(new char[size]);
2✔
420
        std::error_code ec;
2✔
421
        do {
4✔
422
            socket_1.read_some(buffer.get(), size, ec);
4✔
423
        } while (!ec);
4✔
424
        REALM_ASSERT(ec == MiscExtErrors::end_of_input);
2✔
425
    };
2✔
426

427
    std::thread thread(std::move(consumer));
2✔
428

429
#if REALM_HAVE_OPENSSL
1✔
430
    CHECK_SYSTEM_ERROR(ssl_stream_2.handshake(), MiscExtErrors::premature_end_of_input);
1✔
431
#elif REALM_HAVE_SECURE_TRANSPORT
432
    // We replace the CHECK_SYSTEM_ERROR check for "premature end of input"
433
    // with a check for any error code, Mac OS occasionally reports another
434
    // system error. We can revisit the details of the error code later. The
435
    // detailed check is disabled for now to reduce the number of failed unit
436
    // test runs.
437
    CHECK_THROW(ssl_stream_2.handshake(), std::system_error);
1✔
438
#endif
1✔
439

440
    socket_2.close();
2✔
441
    thread.join();
2✔
442
}
2✔
443

444

445
#ifndef _WIN32 // FIXME: winsock doesn't have EPIPE, what's the equivalent?
446
TEST(Util_Network_SSL_BrokenPipeOnHandshakeWrite)
447
{
2✔
448
    network::Service service;
2✔
449
    network::Socket socket_1{service}, socket_2{service};
2✔
450
    network::ssl::Context ssl_context_1;
2✔
451
    network::ssl::Context ssl_context_2;
2✔
452
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
453
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
454
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
455
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
456
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
457
    connect_sockets(socket_1, socket_2);
2✔
458

459
    socket_1.close();
2✔
460

461
    // Fill the kernel level write buffer, to provoke error::broken_pipe.
462
    constexpr std::size_t size = 4096;
2✔
463
    std::unique_ptr<char[]> buffer(new char[size]);
2✔
464
    std::fill(buffer.get(), buffer.get() + size, 0);
2✔
465
    std::error_code ec;
2✔
466
    do {
48✔
467
        socket_2.write_some(buffer.get(), size, ec);
48✔
468
    } while (!ec);
48✔
469
#if REALM_PLATFORM_APPLE
1✔
470
    // Which error we get from writing to a closed socket seems to depend on
471
    // some asynchronous kernel state. If it notices that the socket is closed
472
    // before sending any data we get EPIPE, and if it's after trying to send
473
    // data it's ECONNRESET. EHOSTDOWN is not documented as an error code from
474
    // send() and may be worth investigating once the macOS 12 XNU source is
475
    // released.
476
    REALM_ASSERT(ec == error::broken_pipe || ec == error::connection_reset || ec.value() == EHOSTDOWN);
1!
477
#else
478
    REALM_ASSERT(ec == error::broken_pipe);
1✔
479
#endif
1✔
480

481
    CHECK_SYSTEM_ERROR(ssl_stream_2.handshake(), error::broken_pipe);
2✔
482
}
2✔
483
#endif
484

485

486
TEST(Util_Network_SSL_EndOfInputOnRead)
487
{
2✔
488
    network::Service service_1, service_2;
2✔
489
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
490
    network::ssl::Context ssl_context_1;
2✔
491
    network::ssl::Context ssl_context_2;
2✔
492
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
493
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
494
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
495
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
496
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
497
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
498
    ssl_stream_2.shutdown();
2✔
499
    socket_2.shutdown(network::Socket::shutdown_send);
2✔
500
    char ch;
2✔
501
    CHECK_SYSTEM_ERROR(ssl_stream_1.read_some(&ch, 1), MiscExtErrors::end_of_input);
2✔
502
}
2✔
503

504

505
TEST(Util_Network_SSL_PrematureEndOfInputOnRead)
506
{
2✔
507
    network::Service service_1, service_2;
2✔
508
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
509
    network::ssl::Context ssl_context_1;
2✔
510
    network::ssl::Context ssl_context_2;
2✔
511
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
512
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
513
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
514
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
515
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
516
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
517

518
    socket_2.shutdown(network::Socket::shutdown_send);
2✔
519
    char ch;
2✔
520
    CHECK_SYSTEM_ERROR(ssl_stream_1.read_some(&ch, 1), MiscExtErrors::premature_end_of_input);
2✔
521
}
2✔
522

523

524
#ifndef _WIN32 // FIXME: winsock doesn't have EPIPE, what's the equivalent?
525
TEST(Util_Network_SSL_BrokenPipeOnWrite)
526
{
2✔
527
    network::Service service;
2✔
528
    network::Socket socket_1{service}, socket_2{service};
2✔
529
    network::ssl::Context ssl_context_1;
2✔
530
    network::ssl::Context ssl_context_2;
2✔
531
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
532
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
533
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
534
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
535
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
536
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
537

538
    socket_1.close();
2✔
539

540
    // Fill the kernel level write buffer, to provoke error::broken_pipe.
541
    constexpr std::size_t size = 4096;
2✔
542
    std::unique_ptr<char[]> buffer(new char[size]);
2✔
543
    std::fill(buffer.get(), buffer.get() + size, 0);
2✔
544
    std::error_code ec;
2✔
545
    do {
31✔
546
        socket_2.write_some(buffer.get(), size, ec);
31✔
547
    } while (!ec);
31✔
548
#if REALM_PLATFORM_APPLE
1✔
549
    REALM_ASSERT(ec == error::broken_pipe || ec == error::connection_reset || ec.value() == EHOSTDOWN);
1!
550
#else
551
    REALM_ASSERT(ec == error::broken_pipe);
1✔
552
#endif
1✔
553

554
    char ch = 0;
2✔
555
    CHECK_SYSTEM_ERROR(ssl_stream_2.write(&ch, 1), error::broken_pipe);
2✔
556
}
2✔
557

558

559
TEST(Util_Network_SSL_BrokenPipeOnShutdown)
560
{
2✔
561
    network::Service service;
2✔
562
    network::Socket socket_1{service}, socket_2{service};
2✔
563
    network::ssl::Context ssl_context_1;
2✔
564
    network::ssl::Context ssl_context_2;
2✔
565
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
566
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
567
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
568
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
569
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
570
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
571

572
    socket_1.close();
2✔
573

574
    // Fill the kernel level write buffer, to provoke error::broken_pipe.
575
    constexpr std::size_t size = 4096;
2✔
576
    std::unique_ptr<char[]> buffer(new char[size]);
2✔
577
    std::fill(buffer.get(), buffer.get() + size, 0);
2✔
578
    std::error_code ec;
2✔
579
    do {
78✔
580
        socket_2.write_some(buffer.get(), size, ec);
78✔
581
    } while (!ec);
78✔
582
#if REALM_PLATFORM_APPLE
1✔
583
    REALM_ASSERT(ec == error::broken_pipe || ec == error::connection_reset || ec.value() == EHOSTDOWN);
1!
584
#else
585
    REALM_ASSERT(ec == error::broken_pipe);
1✔
586
#endif
1✔
587

588
    CHECK_SYSTEM_ERROR(ssl_stream_2.shutdown(), error::broken_pipe);
2✔
589
}
2✔
590
#endif
591

592

593
TEST(Util_Network_SSL_ShutdownBeforeCloseNotifyReceived)
594
{
2✔
595
    network::Service service;
2✔
596
    network::Socket socket_1{service}, socket_2{service};
2✔
597
    network::ssl::Context ssl_context_1;
2✔
598
    network::ssl::Context ssl_context_2;
2✔
599
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
600
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
601
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
602
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
603
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
604
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
605

606
    // Shut down peer 1's writing side before it has received a shutdown alert
607
    // from peer 2.
608
    ssl_stream_1.shutdown();
2✔
609
}
2✔
610

611

612
TEST(Util_Network_SSL_ShutdownAfterCloseNotifyReceived)
613
{
2✔
614
    network::Service service;
2✔
615
    network::Socket socket_1{service}, socket_2{service};
2✔
616
    network::ssl::Context ssl_context_1;
2✔
617
    network::ssl::Context ssl_context_2;
2✔
618
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
619
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
620
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
621
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
622
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
623
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
624

625
    // Make sure peer 2 gets an SSL shutdown alert.
626
    ssl_stream_1.shutdown();
2✔
627
    socket_1.shutdown(network::Socket::shutdown_send);
2✔
628

629
    // Make sure peer 2 received the shutdown alert from peer 1 before peer 2
630
    // writes.
631
    char ch;
2✔
632
    CHECK_SYSTEM_ERROR(ssl_stream_2.read_some(&ch, 1), MiscExtErrors::end_of_input);
2✔
633

634
    // Check that peer 2 can stil permform a shutdown operation.
635
    ssl_stream_2.shutdown();
2✔
636
}
2✔
637

638

639
TEST(Util_Network_SSL_WriteAfterCloseNotifyReceived)
640
{
2✔
641
    network::Service service;
2✔
642
    network::Socket socket_1{service}, socket_2{service};
2✔
643
    network::ssl::Context ssl_context_1;
2✔
644
    network::ssl::Context ssl_context_2;
2✔
645
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
646
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
647
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
648
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
649
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
650
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
651

652
    // Shut down peer 1's writing side, such that peer 2 gets an SSL shutdown
653
    // alert.
654
    ssl_stream_1.shutdown();
2✔
655
    socket_1.shutdown(network::Socket::shutdown_send);
2✔
656

657
    // Make sure peer 2 received the shutdown alert from peer 1 before peer 2
658
    // writes.
659
    char ch;
2✔
660
    CHECK_SYSTEM_ERROR(ssl_stream_2.read_some(&ch, 1), MiscExtErrors::end_of_input);
2✔
661

662
    // Make peer 2 Write a message, which must fail....????
663
    const char* message = "hello";
2✔
664
    CHECK_SYSTEM_ERROR(ssl_stream_2.write(message, std::strlen(message)), error::broken_pipe);
2✔
665
}
2✔
666

667
TEST(Util_Network_SSL_BasicSendAndReceive)
668
{
2✔
669
    network::Service service;
2✔
670
    network::Socket socket_1{service}, socket_2{service};
2✔
671
    network::ssl::Context ssl_context_1;
2✔
672
    network::ssl::Context ssl_context_2;
2✔
673
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
674
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
675
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
676
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
677
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
678
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
679

680
    // Make peer 2 Write a message.
681
    const char* message = "hello";
2✔
682
    ssl_stream_2.write(message, std::strlen(message));
2✔
683
    ssl_stream_2.shutdown();
2✔
684
    socket_2.shutdown(network::Socket::shutdown_send);
2✔
685

686
    // Check that peer 1 received the message correctly.
687
    char buffer[256];
2✔
688
    std::error_code ec;
2✔
689
    std::size_t n = ssl_stream_1.read(buffer, sizeof buffer, ec);
2✔
690
    CHECK_EQUAL(MiscExtErrors::end_of_input, ec);
2✔
691
    if (CHECK_EQUAL(std::strlen(message), n))
2✔
692
        CHECK(std::equal(buffer, buffer + n, message));
2✔
693
}
2✔
694

695

696
#if REALM_HAVE_SECURE_TRANSPORT
697

698
template <typename ReadHandler, typename ReadError>
699
void run_ssl_nonzero_length_test(test_util::unit_test::TestContext& test_context, ReadHandler&& read_handler,
700
                                 ReadError&& read_error_callback)
701
{
2✔
702
    network::Service service;
2✔
703
    network::DeadlineTimer run_timer{service};
2✔
704
    network::Socket socket_1{service};
2✔
705
    network::Socket socket_2{service};
2✔
706
    network::ssl::Context ssl_context_1;
2✔
707
    network::ssl::Context ssl_context_2;
2✔
708
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
709
    network::ssl::Stream ssl_stream_1 = {socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
710
    network::ssl::Stream ssl_stream_2 = {socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
711
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
712
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
713
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
714
    network::ReadAheadBuffer rab;
2✔
715

716
    char buffer[50];
2✔
717

718
    auto service_thread = std::thread([&test_context, &service, &run_timer]() {
2✔
719
        run_timer.async_wait(std::chrono::seconds(10), [&test_context](Status status) {
2✔
720
            if (!status.is_ok())
×
721
                return;
722
            test_context.logger->info("run_ssl_nonzero_length_test: service timed out");
723
            abort(); // fail the test if the timer expires
724
        });
725
        service.run();
2✔
726
    });
2✔
727

728
    auto [r_promise, read_future] = util::make_promise_future<void>();
2✔
729
    auto async_read_handler = [&test_context, read_promise = std::move(r_promise),
2✔
730
                               handler = std::move(read_handler)](std::error_code ec, std::size_t n) mutable {
2✔
731
        CHECK_NOT_EQUAL(n, 50);
2✔
732
        handler(test_context, ec, n);
2✔
733
        read_promise.emplace_value();
2✔
734
    };
2✔
735

736
    // Set the error before the read
737
    service.post([&](Status status) {
2✔
738
        if (!status.is_ok())
2✔
739
            return;
740

741
        read_error_callback(test_context, ssl_stream_2);
2✔
742
        ssl_stream_2.async_read(buffer, 50, rab, std::move(async_read_handler));
2✔
743
    });
2✔
744
    read_future.get();
2✔
745

746
    // Shut down stream
747
    auto [s_promise, shutdown_future] = util::make_promise_future<void>();
2✔
748
    auto shutdown_handler = [&test_context, shutdown_promise = std::move(s_promise)](std::error_code ec) mutable {
2✔
749
        CHECK_EQUAL(std::error_code(), ec);
2✔
750
        shutdown_promise.emplace_value();
2✔
751
    };
2✔
752
    service.post([&](Status status) {
2✔
753
        if (!status.is_ok())
2✔
754
            return;
755

756
        ssl_stream_1.async_shutdown(std::move(shutdown_handler));
2✔
757
    });
2✔
758
    shutdown_future.get();
2✔
759

760
    // Stop the service thread after shutdown is complete
761
    service.stop();
2✔
762
    service_thread.join();
2✔
763
}
2✔
764

765
TEST(Util_Network_SSL_Nonzero_Length_Error)
766
{
1✔
767
    using MockSSLError = network::ssl::Stream::MockSSLError;
1✔
768
    auto&& read_handler = [](test_util::unit_test::TestContext& test_context, std::error_code ec, std::size_t n) {
1✔
769
        CHECK_EQUAL(util::MiscExtErrors::premature_end_of_input, ec);
1✔
770
        test_context.logger->info("Util_Network_SSL_Nonzero_Length_Error: n: %1", n);
1✔
771
        CHECK_EQUAL(0, n);
1✔
772
    };
1✔
773
    auto&& read_error_callback = [](test_util::unit_test::TestContext&, network::ssl::Stream& ssl_stream_2) {
1✔
774
        ssl_stream_2.set_mock_ssl_perform_error(
1✔
775
            std::make_unique<MockSSLError>(MockSSLError::Operation::read, static_cast<int>(errSSLClosedAbort), 0));
1✔
776
    };
1✔
777
    run_ssl_nonzero_length_test(test_context, std::move(read_handler), std::move(read_error_callback));
1✔
778
}
1✔
779

780

781
TEST(Util_Network_SSL_Nonzero_Length_EndOfInput)
782
{
1✔
783
    auto&& read_handler = [](test_util::unit_test::TestContext& test_context, std::error_code ec, std::size_t n) {
1✔
784
        CHECK_EQUAL(util::MiscExtErrors::end_of_input, ec);
1✔
785
        test_context.logger->info("Util_Network_SSL_Nonzero_Length_EndOfInput: n: %1", n);
1✔
786
        CHECK_EQUAL(6, n);
1✔
787
    };
1✔
788
    auto&& read_error_callback = [](test_util::unit_test::TestContext&, network::ssl::Stream& ssl_stream_2) {
1✔
789
        using MockSSLError = network::ssl::Stream::MockSSLError;
1✔
790
        ssl_stream_2.set_mock_ssl_perform_error(
1✔
791
            std::make_unique<MockSSLError>(MockSSLError::Operation::read, static_cast<int>(errSSLClosedGraceful), 6));
1✔
792
    };
1✔
793
    run_ssl_nonzero_length_test(test_context, std::move(read_handler), std::move(read_error_callback));
1✔
794
}
1✔
795
#endif
796

797

798
TEST(Util_Network_SSL_StressTest)
799
{
2✔
800
    network::Service service_1, service_2;
2✔
801
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
802
    network::ssl::Context ssl_context_1;
2✔
803
    network::ssl::Context ssl_context_2;
2✔
804
    configure_server_ssl_context_for_test(ssl_context_1);
2✔
805
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
806
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
807
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
808
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
809
    connect_ssl_streams(ssl_stream_1, ssl_stream_2);
2✔
810

811
    constexpr size_t original_size = 0x100000; // 1MiB
2✔
812
    std::unique_ptr<char[]> original_1, original_2;
2✔
813
    original_1.reset(new char[original_size]);
2✔
814
    original_2.reset(new char[original_size]);
2✔
815
    {
2✔
816
        std::mt19937_64 prng{std::random_device()()};
2✔
817
        using lim = std::numeric_limits<char>;
2✔
818
        std::uniform_int_distribution<short> dist{short(lim::min()), short(lim::max())};
2✔
819
        log("Initializing...");
2✔
820
        for (size_t i = 0; i < original_size; ++i)
2,097,154✔
821
            original_1[i] = char(dist(prng));
2,097,152✔
822
        for (size_t i = 0; i < original_size; ++i)
2,097,154✔
823
            original_2[i] = char(dist(prng));
2,097,152✔
824
        log("Initialized");
2✔
825
    }
2✔
826

827
    struct Stats {
2✔
828
        std::uint_fast64_t num_cancellations = 0;
2✔
829
        std::uint_fast64_t num_reads = 0, num_canceled_reads = 0;
2✔
830
        std::uint_fast64_t num_writes = 0, num_canceled_writes = 0;
2✔
831
    };
2✔
832

833
#ifdef _WIN32
834
    // With 512, it would take 9 minutes in 32-bit Debug mode on Windows
835
    constexpr int num_cycles = 32;
836
#else
837
    constexpr int num_cycles = 512;
2✔
838
#endif
2✔
839
    auto thread = [&](int id, network::ssl::Stream& ssl_stream, const char* read_original, const char* write_original,
2✔
840
                      Stats& stats) {
4✔
841
        std::unique_ptr<char[]> read_buffer{new char[original_size]};
4✔
842
        std::mt19937_64 prng{std::random_device()()};
4✔
843
        // Using range 1B -> 32KiB because that undershoots and overshoots in
844
        // equal amounts with respect to the SSL frame size of 16KiB.
845
        std::uniform_int_distribution<size_t> read_write_size_dist(1, 32 * 1024);
4✔
846
        std::uniform_int_distribution<int> delayed_read_write_dist(0, 49);
4✔
847
        network::Service& service = ssl_stream.lowest_layer().get_service();
4✔
848
        network::DeadlineTimer cancellation_timer{service};
4✔
849
        network::DeadlineTimer read_timer{service};
4✔
850
        network::DeadlineTimer write_timer{service};
4✔
851
        bool read_done = false, write_done = false;
4✔
852
        UniqueFunction<void()> shedule_cancellation = [&] {
4✔
853
            cancellation_timer.async_wait(std::chrono::microseconds(10), [&](Status status) {
×
854
                REALM_ASSERT(status.is_ok() || status == ErrorCodes::OperationAborted);
×
855
                if (status == ErrorCodes::OperationAborted)
×
856
                    return;
×
857
                if (read_done && write_done)
×
858
                    return;
×
859
                ssl_stream.lowest_layer().cancel();
×
860
                ++stats.num_cancellations;
×
861
                shedule_cancellation();
×
862
            });
×
863
        };
×
864
        //        shedule_cancellation();
865
        char* read_begin = read_buffer.get();
4✔
866
        char* read_end = read_buffer.get() + original_size;
4✔
867
        int num_read_cycles = 0;
4✔
868
        UniqueFunction<void()> read = [&] {
236,175✔
869
            if (read_begin == read_end) {
236,175✔
870
                log("<R%1>", id);
2,048✔
871
                CHECK(std::equal(read_original, read_original + original_size, read_buffer.get()));
2,048✔
872
                ++num_read_cycles;
2,048✔
873
                if (num_read_cycles == num_cycles) {
2,048✔
874
                    log("End of read %1", id);
4✔
875
                    read_done = true;
4✔
876
                    if (write_done)
4✔
877
                        cancellation_timer.cancel();
4✔
878
                    return;
4✔
879
                }
4✔
880
                read_begin = read_buffer.get();
2,044✔
881
                read_end = read_buffer.get() + original_size;
2,044✔
882
            }
2,044✔
883
            auto handler = [&](std::error_code ec, size_t n) {
236,192✔
884
                REALM_ASSERT(!ec || ec == error::operation_aborted);
236,189!
885
                ++stats.num_reads;
236,189✔
886
                if (ec == error::operation_aborted) {
236,189✔
887
                    ++stats.num_canceled_reads;
×
888
                }
×
889
                else {
236,189✔
890
                    read_begin += n;
236,189✔
891
                }
236,189✔
892
                if (delayed_read_write_dist(prng) == 0) {
236,189✔
893
                    read_timer.async_wait(std::chrono::microseconds(100), [&](Status status) {
4,701✔
894
                        REALM_ASSERT(status.is_ok());
4,701✔
895
                        read();
4,701✔
896
                    });
4,701✔
897
                }
4,701✔
898
                else {
231,488✔
899
                    read();
231,488✔
900
                }
231,488✔
901
            };
236,189✔
902
            char* buffer = read_begin;
236,171✔
903
            size_t size = read_write_size_dist(prng);
236,171✔
904
            size_t max_size = read_end - read_begin;
236,171✔
905
            if (size > max_size)
236,171✔
906
                size = max_size;
3,691✔
907
            ssl_stream.async_read_some(buffer, size, std::move(handler));
236,171✔
908
        };
236,171✔
909
        read();
4✔
910
        const char* write_begin = write_original;
4✔
911
        const char* write_end = write_original + original_size;
4✔
912
        int num_write_cycles = 0;
4✔
913
        UniqueFunction<void()> write = [&] {
153,773✔
914
            if (write_begin == write_end) {
153,773✔
915
                log("<W%1>", id);
2,048✔
916
                ++num_write_cycles;
2,048✔
917
                if (num_write_cycles == num_cycles) {
2,048✔
918
                    log("End of write %1", id);
4✔
919
                    write_done = true;
4✔
920
                    if (read_done)
4✔
921
                        cancellation_timer.cancel();
×
922
                    return;
4✔
923
                }
4✔
924
                write_begin = write_original;
2,044✔
925
                write_end = write_original + original_size;
2,044✔
926
            }
2,044✔
927
            auto handler = [&](std::error_code ec, size_t n) {
153,771✔
928
                REALM_ASSERT(!ec || ec == error::operation_aborted);
153,744!
929
                ++stats.num_writes;
153,744✔
930
                if (ec == error::operation_aborted) {
153,744✔
931
                    ++stats.num_canceled_writes;
×
932
                }
×
933
                else {
153,744✔
934
                    write_begin += n;
153,744✔
935
                }
153,744✔
936
                if (delayed_read_write_dist(prng) == 0) {
153,744✔
937
                    write_timer.async_wait(std::chrono::microseconds(100), [&](Status status) {
3,063✔
938
                        REALM_ASSERT(status.is_ok());
3,063✔
939
                        write();
3,063✔
940
                    });
3,063✔
941
                }
3,063✔
942
                else {
150,681✔
943
                    write();
150,681✔
944
                }
150,681✔
945
            };
153,744✔
946
            const char* data = write_begin;
153,769✔
947
            size_t size = read_write_size_dist(prng);
153,769✔
948
            size_t max_size = write_end - write_begin;
153,769✔
949
            if (size > max_size)
153,769✔
950
                size = max_size;
2,380✔
951
            ssl_stream.async_write_some(data, size, std::move(handler));
153,769✔
952
        };
153,769✔
953
        write();
4✔
954
        service.run();
4✔
955
    };
4✔
956

957
    Stats stats_1, stats_2;
2✔
958
    std::thread thread_1{[&] {
2✔
959
        thread(1, ssl_stream_1, original_1.get(), original_2.get(), stats_1);
2✔
960
    }};
2✔
961
    std::thread thread_2{[&] {
2✔
962
        thread(2, ssl_stream_2, original_2.get(), original_1.get(), stats_2);
2✔
963
    }};
2✔
964
    thread_1.join();
2✔
965
    thread_2.join();
2✔
966

967
    ssl_stream_1.shutdown();
2✔
968
    ssl_stream_2.shutdown();
2✔
969

970
    char ch;
2✔
971
    CHECK_SYSTEM_ERROR(ssl_stream_1.read_some(&ch, 1), MiscExtErrors::end_of_input);
2✔
972
    CHECK_SYSTEM_ERROR(ssl_stream_2.read_some(&ch, 1), MiscExtErrors::end_of_input);
2✔
973

974
    log("Cancellations: %1, %2", stats_1.num_cancellations, stats_2.num_cancellations);
2✔
975
    log("Reads:  %1 (%2 canceled), %3 (%4 canceled)", stats_1.num_reads, stats_1.num_canceled_reads,
2✔
976
        stats_2.num_reads, stats_2.num_canceled_reads);
2✔
977
    log("Writes: %1 (%2 canceled), %3 (%4 canceled)", stats_1.num_writes, stats_1.num_canceled_writes,
2✔
978
        stats_2.num_writes, stats_2.num_canceled_writes);
2✔
979
}
2✔
980

981
// The host name is contained in both the
982
// Common Name and the Subject Alternartive Name
983
// section of the server certificate.
984
TEST(Util_Network_SSL_Certificate_CN_SAN)
985
{
2✔
986
    network::Service service_1, service_2;
2✔
987
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
988
    network::ssl::Context ssl_context_1;
2✔
989
    network::ssl::Context ssl_context_2;
2✔
990

991
    std::string ca_dir = get_test_resource_path();
2✔
992

993
    ssl_context_1.use_certificate_chain_file(ca_dir + "dns-chain.crt.pem");
2✔
994
    ssl_context_1.use_private_key_file(ca_dir + "dns-checked-server.key.pem");
2✔
995
    ssl_context_2.use_verify_file(ca_dir + "crt.pem");
2✔
996

997
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
998
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
999
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
1000
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
1001

1002
    ssl_stream_2.set_verify_mode(network::ssl::VerifyMode::peer);
2✔
1003

1004
    // We expect success because the certificate is signed for www.example.com
1005
    // in both Common Name and SAN.
1006
    ssl_stream_2.set_host_name("www.example.com");
2✔
1007

1008
    connect_sockets(socket_1, socket_2);
2✔
1009

1010
    auto connector = [&] {
2✔
1011
        std::error_code ec;
2✔
1012
        ssl_stream_2.handshake(ec);
2✔
1013
        CHECK_EQUAL(std::error_code(), ec);
2✔
1014
    };
2✔
1015
    auto acceptor = [&] {
2✔
1016
        std::error_code ec;
2✔
1017
        ssl_stream_1.handshake(ec);
2✔
1018
        CHECK_EQUAL(std::error_code(), ec);
2✔
1019
    };
2✔
1020

1021
    std::thread thread_1(std::move(connector));
2✔
1022
    std::thread thread_2(std::move(acceptor));
2✔
1023
    thread_1.join();
2✔
1024
    thread_2.join();
2✔
1025
}
2✔
1026

1027
// The host name is only contained in the
1028
// Subject Alternative Name section of the certificate.
1029
TEST(Util_Network_SSL_Certificate_SAN)
1030
{
2✔
1031
    network::Service service_1, service_2;
2✔
1032
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
1033
    network::ssl::Context ssl_context_1;
2✔
1034
    network::ssl::Context ssl_context_2;
2✔
1035

1036
    std::string ca_dir = get_test_resource_path();
2✔
1037

1038
    ssl_context_1.use_certificate_chain_file(ca_dir + "dns-chain.crt.pem");
2✔
1039
    ssl_context_1.use_private_key_file(ca_dir + "dns-checked-server.key.pem");
2✔
1040
    ssl_context_2.use_verify_file(ca_dir + "crt.pem");
2✔
1041

1042
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
1043
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
1044
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
1045
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
1046

1047
    ssl_stream_2.set_verify_mode(network::ssl::VerifyMode::peer);
2✔
1048

1049
    ssl_stream_2.set_host_name("support.example.com");
2✔
1050

1051
    connect_sockets(socket_1, socket_2);
2✔
1052

1053
    auto connector = [&] {
2✔
1054
        std::error_code ec;
2✔
1055
        ssl_stream_2.handshake(ec);
2✔
1056
        CHECK_EQUAL(std::error_code(), ec);
2✔
1057
    };
2✔
1058
    auto acceptor = [&] {
2✔
1059
        std::error_code ec;
2✔
1060
        ssl_stream_1.handshake(ec);
2✔
1061
        CHECK_EQUAL(std::error_code(), ec);
2✔
1062
    };
2✔
1063

1064
    std::thread thread_1(std::move(connector));
2✔
1065
    std::thread thread_2(std::move(acceptor));
2✔
1066
    thread_1.join();
2✔
1067
    thread_2.join();
2✔
1068
}
2✔
1069

1070

1071
// FIXME: Verification of peer against Common Name is no longer supported in
1072
// Catalina (macOS).
1073
#if REALM_HAVE_OPENSSL || !REALM_HAVE_SECURE_TRANSPORT
1074

1075
// The host name www.example.com is contained in Common Name but not in SAN.
1076
TEST(Util_Network_SSL_Certificate_CN)
1077
{
1✔
1078
    network::Service service_1, service_2;
1✔
1079
    network::Socket socket_1{service_1}, socket_2{service_2};
1✔
1080
    network::ssl::Context ssl_context_1;
1✔
1081
    network::ssl::Context ssl_context_2;
1✔
1082

1083
    std::string ca_dir = get_test_resource_path();
1✔
1084

1085
    ssl_context_1.use_certificate_chain_file(ca_dir + "ip-chain.crt.pem");
1✔
1086
    ssl_context_1.use_private_key_file(ca_dir + "ip-server.key.pem");
1✔
1087
    ssl_context_2.use_verify_file(ca_dir + "crt.pem");
1✔
1088

1089
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
1✔
1090
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
1✔
1091
    ssl_stream_1.set_logger(test_context.logger.get());
1✔
1092
    ssl_stream_2.set_logger(test_context.logger.get());
1✔
1093

1094
    ssl_stream_2.set_verify_mode(network::ssl::VerifyMode::peer);
1✔
1095

1096
    ssl_stream_2.set_host_name("www.example.com");
1✔
1097

1098
    connect_sockets(socket_1, socket_2);
1✔
1099

1100
    auto connector = [&] {
1✔
1101
        std::error_code ec;
1✔
1102
        ssl_stream_2.handshake(ec);
1✔
1103
        CHECK_EQUAL(std::error_code(), ec);
1✔
1104
    };
1✔
1105
    auto acceptor = [&] {
1✔
1106
        std::error_code ec;
1✔
1107
        ssl_stream_1.handshake(ec);
1✔
1108
        CHECK_EQUAL(std::error_code(), ec);
1✔
1109
    };
1✔
1110

1111
    std::thread thread_1(std::move(connector));
1✔
1112
    std::thread thread_2(std::move(acceptor));
1✔
1113
    thread_1.join();
1✔
1114
    thread_2.join();
1✔
1115
}
1✔
1116

1117
#endif // REALM_HAVE_OPENSSL || !REALM_HAVE_SECURE_TRANSPORT
1118

1119
// The ip address is contained in the IP SAN section
1120
// of the certificate. For OpenSSL, we expect failure because we only
1121
// check for DNS. For Secure Transport we get success because the
1122
// ip section is checked. This discrepancy could be resolved in the
1123
// future if deemed important.
1124
TEST(Util_Network_SSL_Certificate_IP)
1125
{
2✔
1126
    network::Service service_1, service_2;
2✔
1127
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
1128
    network::ssl::Context ssl_context_1;
2✔
1129
    network::ssl::Context ssl_context_2;
2✔
1130

1131
    std::string ca_dir = get_test_resource_path();
2✔
1132

1133
    ssl_context_1.use_certificate_chain_file(ca_dir + "ip-chain.crt.pem");
2✔
1134
    ssl_context_1.use_private_key_file(ca_dir + "ip-server.key.pem");
2✔
1135
    ssl_context_2.use_verify_file(ca_dir + "crt.pem");
2✔
1136

1137
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
1138
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
1139
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
1140
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
1141

1142
    ssl_stream_2.set_verify_mode(network::ssl::VerifyMode::peer);
2✔
1143

1144
    ssl_stream_2.set_host_name("127.0.0.1");
2✔
1145

1146
    connect_sockets(socket_1, socket_2);
2✔
1147

1148
    auto connector = [&] {
2✔
1149
        std::error_code ec;
2✔
1150
        ssl_stream_2.handshake(ec);
2✔
1151
#if REALM_HAVE_OPENSSL
1✔
1152
        CHECK_NOT_EQUAL(std::error_code(), ec);
1✔
1153
#elif REALM_HAVE_SECURE_TRANSPORT
1154
        CHECK_EQUAL(std::error_code(), ec);
1✔
1155
#endif
1✔
1156
    };
2✔
1157
    auto acceptor = [&] {
2✔
1158
        std::error_code ec;
2✔
1159
        ssl_stream_1.handshake(ec);
2✔
1160
#if REALM_HAVE_OPENSSL
1✔
1161
        CHECK_NOT_EQUAL(std::error_code(), ec);
1✔
1162
#elif REALM_HAVE_SECURE_TRANSPORT
1163
        CHECK_EQUAL(std::error_code(), ec);
1✔
1164
#endif
1✔
1165
    };
2✔
1166

1167
    std::thread thread_1(std::move(connector));
2✔
1168
    std::thread thread_2(std::move(acceptor));
2✔
1169
    thread_1.join();
2✔
1170
    thread_2.join();
2✔
1171
}
2✔
1172

1173
// The certificate contains incorrect host names.
1174
// We expect the handshake to fail.
1175
TEST(Util_Network_SSL_Certificate_Failure)
1176
{
2✔
1177
    network::Service service_1, service_2;
2✔
1178
    network::Socket socket_1{service_1}, socket_2{service_2};
2✔
1179
    network::ssl::Context ssl_context_1;
2✔
1180
    network::ssl::Context ssl_context_2;
2✔
1181

1182
    std::string ca_dir = get_test_resource_path();
2✔
1183

1184
    ssl_context_1.use_certificate_chain_file(ca_dir + "dns-chain.crt.pem");
2✔
1185
    ssl_context_1.use_private_key_file(ca_dir + "dns-checked-server.key.pem");
2✔
1186
    ssl_context_2.use_verify_file(ca_dir + "crt.pem");
2✔
1187

1188
    network::ssl::Stream ssl_stream_1{socket_1, ssl_context_1, network::ssl::Stream::server};
2✔
1189
    network::ssl::Stream ssl_stream_2{socket_2, ssl_context_2, network::ssl::Stream::client};
2✔
1190
    ssl_stream_1.set_logger(test_context.logger.get());
2✔
1191
    ssl_stream_2.set_logger(test_context.logger.get());
2✔
1192

1193
    ssl_stream_2.set_verify_mode(network::ssl::VerifyMode::peer);
2✔
1194

1195
    // We expect failure because the certificate is signed for www.example.com
1196
    ssl_stream_2.set_host_name("www.another-example.com");
2✔
1197

1198
    connect_sockets(socket_1, socket_2);
2✔
1199

1200
    auto connector = [&] {
2✔
1201
        std::error_code ec;
2✔
1202
        ssl_stream_2.handshake(ec);
2✔
1203
        // Refine this
1204
        CHECK_NOT_EQUAL(std::error_code(), ec);
2✔
1205
    };
2✔
1206
    auto acceptor = [&] {
2✔
1207
        std::error_code ec;
2✔
1208
        ssl_stream_1.handshake(ec);
2✔
1209
        // Refine this
1210
        CHECK_NOT_EQUAL(std::error_code(), ec);
2✔
1211
    };
2✔
1212

1213
    std::thread thread_1(std::move(connector));
2✔
1214
    std::thread thread_2(std::move(acceptor));
2✔
1215
    thread_1.join();
2✔
1216
    thread_2.join();
2✔
1217
}
2✔
1218

1219
#endif // !REALM_MOBILE
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