OpenVPN 3 Core Library
Loading...
Searching...
No Matches
test_proto.cpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
17#include "test_common.hpp"
18
19#include <iostream>
20#include <string>
21#include <sstream>
22#include <deque>
23#include <algorithm>
24#include <cstring>
25#include <limits>
26#include <thread>
27
28#include <gmock/gmock.h>
32
33
34#define OPENVPN_DEBUG
35
36#if !defined(USE_TLS_AUTH) && !defined(USE_TLS_CRYPT)
37// #define USE_TLS_AUTH
38// #define USE_TLS_CRYPT
39#define USE_TLS_CRYPT_V2
40#endif
41
42// Data limits for Blowfish and other 64-bit block-size ciphers
43#ifndef BF
44#define BF 0
45#endif
46#if BF == 1
47#define PROTO_CIPHER "BF-CBC"
48#define TLS_VER_MIN TLSVersion::UNDEF
49#define HANDSHAKE_WINDOW 60
50#define BECOME_PRIMARY_CLIENT 5
51#define BECOME_PRIMARY_SERVER 5
52#define TLS_TIMEOUT_CLIENT 1000
53#define TLS_TIMEOUT_SERVER 1000
54#define FEEDBACK 0
55#elif BF == 2
56#define PROTO_CIPHER "BF-CBC"
57#define TLS_VER_MIN TLSVersion::UNDEF
58#define HANDSHAKE_WINDOW 10
59#define BECOME_PRIMARY_CLIENT 10
60#define BECOME_PRIMARY_SERVER 10
61#define TLS_TIMEOUT_CLIENT 2000
62#define TLS_TIMEOUT_SERVER 1000
63#define FEEDBACK 0
64#elif BF == 3
65#define PROTO_CIPHER "BF-CBC"
66#define TLS_VER_MIN TLSVersion::UNDEF
67#define HANDSHAKE_WINDOW 60
68#define BECOME_PRIMARY_CLIENT 60
69#define BECOME_PRIMARY_SERVER 10
70#define TLS_TIMEOUT_CLIENT 2000
71#define TLS_TIMEOUT_SERVER 1000
72#define FEEDBACK 0
73#elif BF != 0
74#error unknown BF value
75#endif
76
77// TLS timeout
78#ifndef TLS_TIMEOUT_CLIENT
79#define TLS_TIMEOUT_CLIENT 2000
80#endif
81#ifndef TLS_TIMEOUT_SERVER
82#define TLS_TIMEOUT_SERVER 2000
83#endif
84
85// NoisyWire
86#ifndef NOERR
87#define SIMULATE_OOO
88#define SIMULATE_DROPPED
89#define SIMULATE_CORRUPTED
90#endif
91
92// how many virtual seconds between SSL renegotiations
93#ifdef PROTO_RENEG
94#define RENEG PROTO_RENEG
95#else
96#define RENEG 900
97#endif
98
99// feedback
100#ifndef FEEDBACK
101#define FEEDBACK 1
102#else
103#define FEEDBACK 0
104#endif
105
106// number of iterations
107#ifdef PROTO_ITER
108#define ITER PROTO_ITER
109#else
110#define ITER 1000000
111#endif
112
113// number of high-level session iterations
114#ifdef PROTO_SITER
115#define SITER PROTO_SITER
116#else
117#define SITER 1
118#endif
119
120// number of retries for failed test
121#ifndef N_RETRIES
122#define N_RETRIES 2
123#endif
124
125// potentially, the above manifest constants can be converted to variables and modified
126// within the different TEST() functions that replace main() in the original file
127
128// abort if we reach this limit
129// #define DROUGHT_LIMIT 100000
130
131#if !defined(PROTO_VERBOSE) && !defined(QUIET) && ITER <= 10000
132#define VERBOSE
133#endif
134
135#define STRINGIZE1(x) #x
136#define STRINGIZE(x) STRINGIZE1(x)
137
138// setup cipher
139#ifndef PROTO_CIPHER
140#ifdef PROTOv2
141#define PROTO_CIPHER "AES-256-GCM"
142#define TLS_VER_MIN TLSVersion::Type::V1_2
143#else
144#define PROTO_CIPHER "AES-128-CBC"
145#define TLS_VER_MIN TLSVersion::Type::UNDEF
146#endif
147#endif
148
149// setup digest
150#ifndef PROTO_DIGEST
151#define PROTO_DIGEST "SHA1"
152#endif
153
154// setup compressor
155#ifdef PROTOv2
156#ifdef HAVE_LZ4
157#define COMP_METH CompressContext::LZ4v2
158#else
159#define COMP_METH CompressContext::COMP_STUBv2
160#endif
161#else
162#define COMP_METH CompressContext::LZO_STUB
163#endif
164
168#include <openvpn/time/time.hpp>
171#include <openvpn/ssl/proto.hpp>
173
175
176#ifdef USE_MBEDTLS_APPLE_HYBRID
177#define USE_MBEDTLS
178#endif
179
180#if !(defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_APPLE_SSL))
181#error Must define one or more of USE_OPENSSL, USE_MBEDTLS, USE_APPLE_SSL.
182#endif
183
184#if defined(USE_OPENSSL) && (defined(USE_MBEDTLS) || defined(USE_APPLE_SSL))
185#undef USE_OPENSSL
186#define USE_OPENSSL_SERVER
187#elif !defined(USE_OPENSSL) && defined(USE_MBEDTLS)
188#define USE_MBEDTLS_SERVER
189#elif defined(USE_OPENSSL) && !defined(USE_MBEDTLS)
190#define USE_OPENSSL_SERVER
191#else
192#error no server setup
193#endif
194
195#if defined(USE_OPENSSL) || defined(USE_OPENSSL_SERVER)
199#endif
200
201#if defined(USE_APPLE_SSL) || defined(USE_MBEDTLS_APPLE_HYBRID)
205#endif
206
207#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_SERVER)
211#include <mbedtls/debug.h>
212#endif
213
215
216using namespace openvpn;
217
218// server Crypto/SSL/Rand implementation
219#ifdef USE_MBEDTLS_SERVER
220typedef MbedTLSCryptoAPI ServerCryptoAPI;
221typedef MbedTLSContext ServerSSLAPI;
222typedef MbedTLSRandom ServerRandomAPI;
223#elif defined(USE_OPENSSL_SERVER)
224using ServerCryptoAPI = OpenSSLCryptoAPI;
225using ServerSSLAPI = OpenSSLContext;
226using ServerRandomAPI = OpenSSLRandom;
227#else
228#error No server SSL implementation defined
229#endif
230
231// client SSL implementation can be OpenSSL, Apple SSL, or MbedTLS
232#ifdef USE_MBEDTLS
233#if defined(USE_MBEDTLS_APPLE_HYBRID)
234typedef AppleCryptoAPI ClientCryptoAPI;
235#else
236typedef MbedTLSCryptoAPI ClientCryptoAPI;
237#endif
238typedef MbedTLSContext ClientSSLAPI;
239typedef MbedTLSRandom ClientRandomAPI;
240#elif defined(USE_APPLE_SSL)
241typedef AppleCryptoAPI ClientCryptoAPI;
242typedef AppleSSLContext ClientSSLAPI;
243typedef AppleRandom ClientRandomAPI;
244#elif defined(USE_OPENSSL)
245using ClientCryptoAPI = OpenSSLCryptoAPI;
246using ClientSSLAPI = OpenSSLContext;
247using ClientRandomAPI = OpenSSLRandom;
248#else
249#error No client SSL implementation defined
250#endif
251
252const char message[] = "Message _->_ 0000000000 It was a bright cold day in April, and the clocks\n"
253 "were striking thirteen. Winston Smith, his chin nuzzled\n"
254 "into his breast in an effort to escape the vile wind,\n"
255 "slipped quickly through the glass doors of Victory\n"
256 "Mansions, though not quickly enough to prevent a\n"
257 "swirl of gritty dust from entering along with him.\n"
258#ifdef LARGE_MESSAGE
259 "It was a bright cold day in April, and the clocks\n"
260 "were striking thirteen. Winston Smith, his chin nuzzled\n"
261 "into his breast in an effort to escape the vile wind,\n"
262 "slipped quickly through the glass doors of Victory\n"
263 "Mansions, though not quickly enough to prevent a\n"
264 "swirl of gritty dust from entering along with him.\n"
265 "It was a bright cold day in April, and the clocks\n"
266 "were striking thirteen. Winston Smith, his chin nuzzled\n"
267 "into his breast in an effort to escape the vile wind,\n"
268 "slipped quickly through the glass doors of Victory\n"
269 "Mansions, though not quickly enough to prevent a\n"
270 "swirl of gritty dust from entering along with him.\n"
271 "It was a bright cold day in April, and the clocks\n"
272 "were striking thirteen. Winston Smith, his chin nuzzled\n"
273 "into his breast in an effort to escape the vile wind,\n"
274 "slipped quickly through the glass doors of Victory\n"
275 "Mansions, though not quickly enough to prevent a\n"
276 "swirl of gritty dust from entering along with him.\n"
277 "It was a bright cold day in April, and the clocks\n"
278 "were striking thirteen. Winston Smith, his chin nuzzled\n"
279 "into his breast in an effort to escape the vile wind,\n"
280 "slipped quickly through the glass doors of Victory\n"
281 "Mansions, though not quickly enough to prevent a\n"
282 "swirl of gritty dust from entering along with him.\n"
283#endif
284 ;
285
286// A "Drought" measures the maximum period of time between
287// any two successive events. Used to measure worst-case
288// packet loss.
290{
291 public:
292 OPENVPN_SIMPLE_EXCEPTION(drought_limit_exceeded);
293
294 DroughtMeasure(const std::string &name_arg, TimePtr now_arg)
295 : now(now_arg), name(name_arg)
296 {
297 }
298
299 void event()
300 {
301 if (last_event.defined())
302 {
303 Time::Duration since_last = *now - last_event;
304 if (since_last > drought)
305 {
306 drought = since_last;
307#if defined(VERBOSE) || defined(DROUGHT_LIMIT)
308 {
309 const unsigned int r = drought.raw();
310#if defined(VERBOSE)
311 std::cout << "*** Drought " << name << " has reached " << r << "\n";
312#endif
313#ifdef DROUGHT_LIMIT
314 if (r > DROUGHT_LIMIT)
315 throw drought_limit_exceeded();
316#endif
317 }
318#endif
319 }
320 }
321 last_event = *now;
322 }
323
324 Time::Duration operator()() const
325 {
326 return drought;
327 }
328
329 private:
332 Time::Duration drought;
333 std::string name;
334};
335
336// test the OpenVPN protocol implementation in ProtoContext
338{
339 /* Callback methods that are not used */
340 void active(bool primary) override
341 {
342 }
343
344 bool supports_epoch_data() override
345 {
346 return true;
347 }
348
349 public:
350 OPENVPN_EXCEPTION(session_invalidated);
351
353 const SessionStats::Ptr &stats)
354 : proto_context(this, config, stats),
355 control_drought("control", config->now),
356 data_drought("data", config->now),
358 {
359 // zero progress value
360 std::memset(progress_, 0, 11);
361 }
362
369
370 void initial_app_send(const char *msg)
371 {
373 const size_t msglen = std::strlen(msg) + 1;
374 BufferAllocated app_buf((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
375 copy_progress(app_buf);
376 control_send(std::move(app_buf));
377 proto_context.flush(true);
378 }
379
380 void app_send_templ_init(const char *msg)
381 {
383 const size_t msglen = std::strlen(msg) + 1;
384 templ = BufferAllocatedRc::Create((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
385 proto_context.flush(true);
386 }
387
389 {
390#if !FEEDBACK
391 if (bool(iteration++ & 1) == is_server())
392 {
393 modmsg(templ);
394 BufferAllocated app_buf(*templ);
395 control_send(std::move(app_buf));
396 flush(true);
398 }
399#endif
400 }
401
403 {
405 {
407 return true;
408 }
409 return false;
410 }
411
412 void control_send(BufferPtr &&app_bp)
413 {
414 app_bytes_ += app_bp->size();
415 proto_context.control_send(std::move(app_bp));
416 }
417
419 {
420 app_bytes_ += app_buf.size();
421 proto_context.control_send(std::move(app_buf));
422 }
423
425 {
428 bp->write((unsigned char *)str, std::strlen(str));
429 data_encrypt(*bp);
430 return bp;
431 }
432
434 {
436 }
437
439 {
440 proto_context.data_decrypt(type, in_out);
441 if (!in_out.empty())
442 {
443 data_bytes_ += in_out.size();
445 }
446 }
447
448 size_t net_bytes() const
449 {
450 return net_bytes_;
451 }
452 size_t app_bytes() const
453 {
454 return app_bytes_;
455 }
456 size_t data_bytes() const
457 {
458 return data_bytes_;
459 }
460 size_t n_control_recv() const
461 {
462 return n_control_recv_;
463 }
464 size_t n_control_send() const
465 {
466 return n_control_send_;
467 }
468
469 const char *progress() const
470 {
471 return progress_;
472 }
473
474 void finalize()
475 {
478 }
479
481 {
483 throw session_invalidated(Error::name(proto_context.invalidation_reason()));
484 }
485
487 {
488 disable_xmit_ = true;
489 }
490
492
493 std::deque<BufferPtr> net_out;
494
497
498 private:
499 void control_net_send(const Buffer &net_buf) override
500 {
501 if (disable_xmit_)
502 return;
503 net_bytes_ += net_buf.size();
505 }
506
507 void control_recv(BufferPtr &&app_bp) override
508 {
510 work.swap(app_bp);
511 if (work->size() >= 23)
512 std::memcpy(progress_, work->data() + 13, 10);
513
514#ifdef VERBOSE
515 {
516 const ssize_t trunc = 64;
517 const std::string show((char *)work->data(), trunc);
518 std::cout << now().raw() << " " << mode().str() << " " << show << "\n";
519 }
520#endif
521#if FEEDBACK
522 modmsg(work);
523 control_send(std::move(work));
524#endif
527 }
528
530 {
531 if (progress_[0]) // make sure progress was initialized
532 std::memcpy(buf.data() + 13, progress_, 10);
533 }
534
535 void modmsg(BufferPtr &buf)
536 {
537 char *msg = (char *)buf->data();
539 {
540 msg[8] = 'S';
541 msg[11] = 'C';
542 }
543 else
544 {
545 msg[8] = 'C';
546 msg[11] = 'S';
547 }
548
549 // increment embedded number
550 for (int i = 22; i >= 13; i--)
551 {
552 if (msg[i] != '9')
553 {
554 msg[i]++;
555 break;
556 }
557 msg[i] = '0';
558 }
559 }
560
562 size_t app_bytes_ = 0;
563 size_t net_bytes_ = 0;
564 size_t data_bytes_ = 0;
565 size_t n_control_send_ = 0;
566 size_t n_control_recv_ = 0;
568#if !FEEDBACK
569 size_t iteration = 0;
570#endif
571 char progress_[11];
572 bool disable_xmit_ = false;
573};
574
576{
578
579 public:
581 const SessionStats::Ptr &stats)
582 : TestProto(config, stats)
583 {
584 }
585
586 private:
587 void client_auth(Buffer &buf) override
588 {
589 const std::string username("foo");
590 const std::string password("bar");
591 ProtoContext::write_auth_string(username, buf);
592 ProtoContext::write_auth_string(password, buf);
593 }
594};
595
597{
598
599 public:
600 void start()
601 {
603 }
604
606
607
609 const SessionStats::Ptr &stats)
610 : TestProto(config, stats)
611 {
612 }
613
614 private:
615 void server_auth(const std::string &username,
616 const SafeString &password,
617 const std::string &peer_info,
618 const AuthCert::Ptr &auth_cert) override
619 {
620#ifdef VERBOSE
621 std::cout << "**** AUTHENTICATE " << username << '/' << password << " PEER INFO:\n";
622 std::cout << peer_info;
623#endif
624 if (username != "foo" || password != "bar")
625 throw auth_failed();
626 }
627};
628
629// Simulate a noisy transmission channel where packets can be dropped,
630// reordered, or corrupted.
632{
633 public:
634 NoisyWire(const std::string &title_arg,
635 TimePtr now_arg,
636 RandomAPI &rand_arg,
637 const unsigned int reorder_prob_arg,
638 const unsigned int drop_prob_arg,
639 const unsigned int corrupt_prob_arg)
640 : title(title_arg),
641#ifdef VERBOSE
642 now(now_arg),
643#endif
644 random(rand_arg),
645 reorder_prob(reorder_prob_arg),
646 drop_prob(drop_prob_arg),
647 corrupt_prob(corrupt_prob_arg)
648 {
649 }
650
651 template <typename T1, typename T2>
652 void xfer(T1 &a, T2 &b)
653 {
654 // check for errors
655 a.check_invalidated();
656 b.check_invalidated();
657
658 // need to retransmit?
659 if (a.do_housekeeping())
660 {
661#ifdef VERBOSE
662 std::cout << now->raw() << " " << title << " Housekeeping\n";
663#endif
664 }
665
666 // queue a control channel packet
667 a.app_send_templ();
668
669 // queue a data channel packet
670 if (a.proto_context.data_channel_ready())
671 {
672 BufferPtr bp = a.data_encrypt_string("Waiting for godot A... Waiting for godot B... Waiting for godot C... Waiting for godot D... Waiting for godot E... Waiting for godot F... Waiting for godot G... Waiting for godot H... Waiting for godot I... Waiting for godot J...");
673 wire.push_back(bp);
674 }
675
676 // transfer network packets from A -> wire
677 while (!a.net_out.empty())
678 {
679 BufferPtr bp = a.net_out.front();
680#ifdef VERBOSE
681 std::cout << now->raw() << " " << title << " " << a.dump_packet(*bp) << "\n";
682#endif
683 a.net_out.pop_front();
684 wire.push_back(bp);
685 }
686
687 // transfer network packets from wire -> B
688 while (true)
689 {
690 BufferPtr bp = recv();
691 if (!bp)
692 break;
693 typename ProtoContext::PacketType pt = b.proto_context.packet_type(*bp);
694 if (pt.is_control())
695 {
696#ifdef VERBOSE
697 if (!b.control_net_validate(pt, *bp)) // not strictly necessary since control_net_recv will also validate
698 std::cout << now->raw() << " " << title << " CONTROL PACKET VALIDATION FAILED\n";
699#endif
700 b.proto_context.control_net_recv(pt, std::move(bp));
701 }
702 else if (pt.is_data())
703 {
704 try
705 {
706 b.data_decrypt(pt, *bp);
707#ifdef VERBOSE
708 if (bp->size())
709 {
710 const std::string show((char *)bp->data(), std::min(bp->size(), size_t(40)));
711 std::cout << now->raw() << " " << title << " DATA CHANNEL DECRYPT: " << show << "\n";
712 }
713#endif
714 }
715 catch ([[maybe_unused]] const std::exception &e)
716 {
717#ifdef VERBOSE
718 std::cout << now->raw() << " " << title << " Exception on data channel decrypt: " << e.what() << "\n";
719#endif
720 }
721 }
722 else
723 {
724#ifdef VERBOSE
725 std::cout << now->raw() << " " << title << " KEY_STATE_ERROR\n";
726#endif
727 b.proto_context.stat().error(Error::KEY_STATE_ERROR);
728 }
729
730#ifdef SIMULATE_UDP_AMPLIFY_ATTACK
731 if (b.proto_context.is_state_client_wait_reset_ack())
732 {
733 b.disable_xmit();
734#ifdef VERBOSE
735 std::cout << now->raw() << " " << title << " SIMULATE_UDP_AMPLIFY_ATTACK disable client xmit\n";
736#endif
737 }
738#endif
739 }
740 b.proto_context.flush(true);
741 }
742
743 private:
745 {
746#ifdef SIMULATE_OOO
747 // simulate packets being received out of order
748 if (wire.size() >= 2 && !rand(reorder_prob))
749 {
750 const size_t i = random.randrange(wire.size() - 1) + 1;
751#ifdef VERBOSE
752 std::cout << now->raw() << " " << title << " Simulating packet reordering " << i << " -> 0\n";
753#endif
754 std::swap(wire[0], wire[i]);
755 }
756#endif
757
758 if (!wire.empty())
759 {
760 BufferPtr bp = wire.front();
761 wire.pop_front();
762
763#ifdef VERBOSE
764 std::cout << now->raw() << " " << title << " Received packet, size=" << bp->size() << "\n";
765#endif
766
767#ifdef SIMULATE_DROPPED
768 // simulate dropped packet
769 if (!rand(drop_prob))
770 {
771#ifdef VERBOSE
772 std::cout << now->raw() << " " << title << " Simulating a dropped packet\n";
773#endif
774 return BufferPtr();
775 }
776#endif
777
778#ifdef SIMULATE_CORRUPTED
779 // simulate corrupted packet
780 if (!bp->empty() && !rand(corrupt_prob))
781 {
782#ifdef VERBOSE
783 std::cout << now->raw() << " " << title << " Simulating a corrupted packet\n";
784#endif
785 const size_t pos = random.randrange(bp->size());
786 const unsigned char value = random.randrange(std::numeric_limits<unsigned char>::max());
787 (*bp)[pos] = value;
788 }
789#endif
790 return bp;
791 }
792
793 return BufferPtr();
794 }
795
796 unsigned int rand(const unsigned int prob)
797 {
798 if (prob)
799 return random.randrange(prob);
800 return 1;
801 }
802
803 std::string title;
804#ifdef VERBOSE
805 TimePtr now;
806#endif
808 unsigned int reorder_prob;
809 unsigned int drop_prob;
810 unsigned int corrupt_prob;
811 std::deque<BufferPtr> wire;
812};
813
814class MySessionStats : public SessionStats
815{
816 public:
818
820 {
821 std::memset(errors, 0, sizeof(errors));
822 }
823
824 void error(const size_t err_type, const std::string *text = nullptr) override
825 {
826 if (err_type < Error::N_ERRORS)
827 ++errors[err_type];
828 }
829
831 {
832 if (type < Error::N_ERRORS)
833 return errors[type];
834 return 0;
835 }
836
837 void show_error_counts() const
838 {
839 for (size_t i = 0; i < Error::N_ERRORS; ++i)
840 {
841 count_t c = errors[i];
842 if (c)
843 std::cerr << Error::name(i) << " : " << c << '\n';
844 }
845 }
846
847 private:
849};
850
855static auto create_client_ssl_config(Frame::Ptr frame, ClientRandomAPI::Ptr rng, bool tls_version_mismatch = false)
856{
857 const std::string client_crt = read_text(TEST_KEYCERT_DIR "client.crt");
858 const std::string client_key = read_text(TEST_KEYCERT_DIR "client.key");
859 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
860
861 // client config
862 ClientSSLAPI::Config::Ptr cc(new ClientSSLAPI::Config());
863 cc->set_mode(Mode(Mode::CLIENT));
864 cc->set_frame(frame);
865 cc->set_rng(rng);
866#ifdef USE_APPLE_SSL
867 cc->load_identity("etest");
868#else
869 cc->load_ca(ca_crt, true);
870 cc->load_cert(client_crt);
871 cc->load_private_key(client_key);
872#endif
873 if (tls_version_mismatch)
874 cc->set_tls_version_max(TLSVersion::Type::V1_2);
875 else
876 cc->set_tls_version_min(TLS_VER_MIN);
877#ifdef VERBOSE
878 cc->set_debug_level(1);
879#endif
880 return cc;
881}
882
883static auto create_client_proto_context(ClientSSLAPI::Config::Ptr cc, Frame::Ptr frame, ClientRandomAPI::Ptr rng, MySessionStats::Ptr cli_stats, Time &time, const std::string &tls_crypt_v2_key_fn = "")
884
885{
886 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
887 const std::string tls_crypt_v2_client_key = tls_crypt_v2_key_fn.empty()
888 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-client.key")
889 : read_text(TEST_KEYCERT_DIR + tls_crypt_v2_key_fn);
890
891 // client ProtoContext config
892 using ClientProtoContext = ProtoContext;
893 ClientProtoContext::ProtoConfig::Ptr cp(new ClientProtoContext::ProtoConfig);
894 cp->ssl_factory = cc->new_factory();
895 CryptoAlgs::allow_default_dc_algs<ClientCryptoAPI>(cp->ssl_factory->libctx(), false, false);
896 cp->dc.set_factory(new CryptoDCSelect<ClientCryptoAPI>(cp->ssl_factory->libctx(), frame, cli_stats, rng));
897 cp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ClientCryptoAPI>());
898 cp->frame = std::move(frame);
899 cp->now = &time;
900 cp->rng = rng;
901 cp->prng = rng;
902 cp->protocol = Protocol(Protocol::UDPv4);
903 cp->layer = Layer(Layer::OSI_LAYER_3);
904#ifdef PROTOv2
905 cp->enable_op32 = true;
906 cp->remote_peer_id = 100;
907#endif
908 cp->comp_ctx = CompressContext(COMP_METH, false);
909 cp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
910 cp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
911
912#ifdef USE_TLS_AUTH
913 cp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ClientCryptoAPI>());
914 cp->tls_auth_key.parse(tls_auth_key);
915 cp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
916 cp->key_direction = 0;
917#endif
918#ifdef USE_TLS_CRYPT
919 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
920 cp->tls_crypt_key.parse(tls_auth_key);
921 cp->set_tls_crypt_algs();
922 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
923#endif
924#ifdef USE_TLS_CRYPT_V2
925 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
926 cp->set_tls_crypt_algs();
927 {
928 TLSCryptV2ClientKey tls_crypt_v2_key(cp->tls_crypt_context);
929 tls_crypt_v2_key.parse(tls_crypt_v2_client_key);
930 tls_crypt_v2_key.extract_key(cp->tls_crypt_key);
931 tls_crypt_v2_key.extract_wkc(cp->wkc);
932 }
933 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
934#endif
935#ifdef HANDSHAKE_WINDOW
936 cp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
937#elif SITER > 1
938 cp->handshake_window = Time::Duration::seconds(30);
939#else
940 cp->handshake_window = Time::Duration::seconds(18); // will cause a small number of handshake failures
941#endif
942#ifdef BECOME_PRIMARY_CLIENT
943 cp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_CLIENT);
944#else
945 cp->become_primary = cp->handshake_window;
946#endif
947 cp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_CLIENT);
948#ifdef CLIENT_NO_RENEG
949 cp->renegotiate = Time::Duration::infinite();
950#else
951 cp->renegotiate = Time::Duration::seconds(RENEG);
952#endif
953 cp->expire = cp->renegotiate + cp->renegotiate;
954 cp->keepalive_ping = Time::Duration::seconds(5);
955 cp->keepalive_timeout = Time::Duration::seconds(60);
956 cp->keepalive_timeout_early = cp->keepalive_timeout;
957
958#ifdef VERBOSE
959 std::cout << "CLIENT OPTIONS: " << cp->options_string() << "\n";
960 std::cout << "CLIENT PEER INFO:\n";
961 std::cout << cp->peer_info_string();
962#endif
963 return cp;
964}
965
966// execute the unit test in one thread
967int test(const int thread_num,
968 bool use_tls_ekm,
969 bool tls_version_mismatch,
970 const std::string &tls_crypt_v2_key_fn = "",
971 bool use_tls_auth_with_tls_crypt_v2 = false)
972{
973 try
974 {
975 // frame
976 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
977
978 // RNG
979 ClientRandomAPI::Ptr prng_cli(new ClientRandomAPI());
980 ServerRandomAPI::Ptr prng_serv(new ServerRandomAPI());
981 MTRand rng_noncrypto;
982
983 // init simulated time
984 Time time;
985 const Time::Duration time_step = Time::Duration::binary_ms(100);
986
987 // config files
988 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
989 const std::string server_crt = read_text(TEST_KEYCERT_DIR "server.crt");
990 const std::string server_key = read_text(TEST_KEYCERT_DIR "server.key");
991 const std::string dh_pem = read_text(TEST_KEYCERT_DIR "dh.pem");
992 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
993 const std::string tls_crypt_v2_server_key = tls_crypt_v2_key_fn.empty()
994 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-server.key")
995 : "";
996
997 // client config
998 ClientSSLAPI::Config::Ptr cc = create_client_ssl_config(frame, prng_cli, tls_version_mismatch);
999 MySessionStats::Ptr cli_stats(new MySessionStats);
1000
1001 auto cp = create_client_proto_context(std::move(cc), frame, prng_cli, cli_stats, time, tls_crypt_v2_key_fn);
1002 if (use_tls_ekm)
1003 cp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1004
1005 // server config
1006 MySessionStats::Ptr serv_stats(new MySessionStats);
1007
1008 ServerSSLAPI::Config::Ptr sc(new ClientSSLAPI::Config());
1009 sc->set_mode(Mode(Mode::SERVER));
1010 sc->set_frame(frame);
1011 sc->set_rng(prng_serv);
1012 sc->load_ca(ca_crt, true);
1013 sc->load_cert(server_crt);
1014 sc->load_private_key(server_key);
1015 sc->load_dh(dh_pem);
1016 sc->set_tls_version_min(tls_version_mismatch ? TLSVersion::Type::V1_3 : TLS_VER_MIN);
1017#ifdef VERBOSE
1018 sc->set_debug_level(1);
1019#endif
1020
1021 // server ProtoContext config
1022 using ServerProtoContext = ProtoContext;
1023 ServerProtoContext::ProtoConfig::Ptr sp(new ServerProtoContext::ProtoConfig);
1024 sp->ssl_factory = sc->new_factory();
1025 sp->dc.set_factory(new CryptoDCSelect<ServerCryptoAPI>(sp->ssl_factory->libctx(), frame, serv_stats, prng_serv));
1026 sp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ServerCryptoAPI>());
1027 sp->frame = frame;
1028 sp->now = &time;
1029 sp->rng = prng_serv;
1030 sp->prng = prng_serv;
1031 sp->protocol = Protocol(Protocol::UDPv4);
1032 sp->layer = Layer(Layer::OSI_LAYER_3);
1033#ifdef PROTOv2
1034 sp->enable_op32 = true;
1035 sp->remote_peer_id = 101;
1036#endif
1037 sp->comp_ctx = CompressContext(COMP_METH, false);
1038 sp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
1039 sp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1040 if (use_tls_ekm)
1041 sp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1042#ifdef USE_TLS_AUTH
1043 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1044 sp->tls_auth_key.parse(tls_auth_key);
1045 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1046 sp->key_direction = 1;
1047#endif
1048#ifdef USE_TLS_CRYPT
1049 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1050 sp->tls_crypt_key.parse(tls_auth_key);
1051 sp->set_tls_crypt_algs();
1052 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
1053#endif
1054#ifdef USE_TLS_CRYPT_V2
1055 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1056
1057 if (tls_crypt_v2_key_fn.empty())
1058 {
1059 TLSCryptV2ServerKey tls_crypt_v2_key;
1060 tls_crypt_v2_key.parse(tls_crypt_v2_server_key);
1061 tls_crypt_v2_key.extract_key(sp->tls_crypt_key);
1062 }
1063
1064 sp->set_tls_crypt_algs();
1065 sp->tls_crypt_metadata_factory.reset(new CryptoTLSCryptMetadataFactory());
1066 sp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
1067 sp->tls_crypt_v2_serverkey_id = !tls_crypt_v2_key_fn.empty();
1068 sp->tls_crypt_v2_serverkey_dir = TEST_KEYCERT_DIR;
1069
1070 if (use_tls_auth_with_tls_crypt_v2)
1071 {
1072 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1073 sp->tls_auth_key.parse(tls_auth_key);
1074 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1075 sp->key_direction = 1;
1076 }
1077#endif
1078#ifdef HANDSHAKE_WINDOW
1079 sp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
1080#elif SITER > 1
1081 sp->handshake_window = Time::Duration::seconds(30);
1082#else
1083 sp->handshake_window = Time::Duration::seconds(17) + Time::Duration::binary_ms(512);
1084#endif
1085#ifdef BECOME_PRIMARY_SERVER
1086 sp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_SERVER);
1087#else
1088 sp->become_primary = sp->handshake_window;
1089#endif
1090 sp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_SERVER);
1091#ifdef SERVER_NO_RENEG
1092 sp->renegotiate = Time::Duration::infinite();
1093#else
1094 // NOTE: if we don't add sp->handshake_window, both client and server reneg-sec (RENEG)
1095 // will be equal and will therefore occasionally collide. Such collisions can sometimes
1096 // produce this OpenSSL error:
1097 // OpenSSLContext::SSL::read_cleartext: BIO_read failed, cap=400 status=-1: error:140E0197:SSL routines:SSL_shutdown:shutdown while in init
1098 // The issue was introduced by this patch in OpenSSL:
1099 // https://github.com/openssl/openssl/commit/64193c8218540499984cd63cda41f3cd491f3f59
1100 sp->renegotiate = Time::Duration::seconds(RENEG) + sp->handshake_window;
1101#endif
1102 sp->expire = sp->renegotiate + sp->renegotiate;
1103 sp->keepalive_ping = Time::Duration::seconds(5);
1104 sp->keepalive_timeout = Time::Duration::seconds(60);
1105 sp->keepalive_timeout_early = Time::Duration::seconds(10);
1106
1107#ifdef VERBOSE
1108 std::cout << "SERVER OPTIONS: " << sp->options_string() << "\n";
1109 std::cout << "SERVER PEER INFO:\n";
1110 std::cout << sp->peer_info_string();
1111#endif
1112
1113 TestProtoClient cli_proto(cp, cli_stats);
1114 TestProtoServer serv_proto(sp, serv_stats);
1115
1116 for (int i = 0; i < SITER; ++i)
1117 {
1118#ifdef VERBOSE
1119 std::cout << "***** SITER " << i << "\n";
1120#endif
1121 cli_proto.reset();
1122 serv_proto.reset();
1123
1124 NoisyWire client_to_server("Client -> Server", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1125 NoisyWire server_to_client("Server -> Client", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1126
1127 int j = -1;
1128 try
1129 {
1130#if FEEDBACK
1131 // start feedback loop
1132 cli_proto.initial_app_send(message);
1133 serv_proto.start();
1134#else
1135 cli_proto.app_send_templ_init(message);
1136 serv_proto.app_send_templ_init(message);
1137#endif
1138
1139 // message loop
1140 for (j = 0; j < ITER; ++j)
1141 {
1142 client_to_server.xfer(cli_proto, serv_proto);
1143 server_to_client.xfer(serv_proto, cli_proto);
1144 time += time_step;
1145 }
1146 }
1147 catch (const std::exception &e)
1148 {
1149 std::cerr << "Exception[" << i << '/' << j << "]: " << e.what() << '\n';
1150 return 1;
1151 }
1152 }
1153
1154 cli_proto.finalize();
1155 serv_proto.finalize();
1156
1157 const size_t ab = cli_proto.app_bytes() + serv_proto.app_bytes();
1158 const size_t nb = cli_proto.net_bytes() + serv_proto.net_bytes();
1159 const size_t db = cli_proto.data_bytes() + serv_proto.data_bytes();
1160
1161 std::cerr << "*** app bytes=" << ab
1162 << " net_bytes=" << nb
1163 << " data_bytes=" << db
1164 << " prog=" << cli_proto.progress() << '/' << serv_proto.progress()
1165#if !FEEDBACK
1166 << " CTRL=" << cli_proto.n_control_recv() << '/' << cli_proto.n_control_send() << '/' << serv_proto.n_control_recv() << '/' << serv_proto.n_control_send()
1167#endif
1168 << " D=" << cli_proto.control_drought().raw() << '/' << cli_proto.data_drought().raw() << '/' << serv_proto.control_drought().raw() << '/' << serv_proto.data_drought().raw()
1169 << " N=" << cli_proto.proto_context.negotiations() << '/' << serv_proto.proto_context.negotiations()
1170 << " SH=" << cli_proto.proto_context.slowest_handshake().raw() << '/' << serv_proto.proto_context.slowest_handshake().raw()
1171 << " HE=" << cli_stats->get_error_count(Error::HANDSHAKE_TIMEOUT) << '/' << serv_stats->get_error_count(Error::HANDSHAKE_TIMEOUT)
1172 << '\n';
1173
1174#ifdef STATS
1175 std::cerr << "-------- CLIENT STATS --------\n";
1176 cli_stats->show_error_counts();
1177 std::cerr << "-------- SERVER STATS --------\n";
1178 serv_stats->show_error_counts();
1179#endif
1180#ifdef OPENVPN_MAX_DATALIMIT_BYTES
1181 std::cerr << "------------------------------\n";
1182 std::cerr << "MAX_DATALIMIT_BYTES=" << DataLimit::max_bytes() << "\n";
1183#endif
1184 }
1185 catch (const std::exception &e)
1186 {
1187 std::cerr << "Exception: " << e.what() << '\n';
1188 return 1;
1189 }
1190 return 0;
1191}
1192
1193int test_retry(const int thread_num,
1194 const int n_retries,
1195 bool use_tls_ekm,
1196 bool tls_version_mismatch = false,
1197 const std::string &tls_crypt_v2_key_fn = "",
1198 bool use_tls_auth_with_tls_crypt_v2 = false)
1199{
1200 int ret = 1;
1201 for (int i = 0; i < n_retries; ++i)
1202 {
1203 ret = test(thread_num, use_tls_ekm, tls_version_mismatch, tls_crypt_v2_key_fn, use_tls_auth_with_tls_crypt_v2);
1204 if (!ret)
1205 return 0;
1206 std::cout << "Retry " << (i + 1) << '/' << n_retries << '\n';
1207 }
1208 std::cout << "Failed\n";
1209 return ret;
1210}
1211
1212class ProtoUnitTest : public testing::Test
1213{
1214 // Sets up the test fixture.
1215 void SetUp() override
1216 {
1217#ifdef USE_MBEDTLS
1218 mbedtls_debug_set_threshold(1);
1219#endif
1220
1222
1223#ifdef PROTO_VERBOSE
1225#else
1227#endif
1228 }
1229
1230 // Tears down the test fixture.
1231 void TearDown() override
1232 {
1233#ifdef USE_MBEDTLS
1234 mbedtls_debug_set_threshold(4);
1235#endif
1238 }
1239};
1240
1241TEST_F(ProtoUnitTest, BaseSingleThreadTlsEkm)
1242{
1243 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1244 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1245
1246 int ret = 0;
1247
1248 ret = test_retry(1, N_RETRIES, true);
1249
1250 EXPECT_EQ(ret, 0);
1251}
1252
1253TEST_F(ProtoUnitTest, BaseSingleThreadNoTlsEkm)
1254{
1255 int ret = 0;
1256
1257 ret = test_retry(1, N_RETRIES, false);
1258
1259 EXPECT_EQ(ret, 0);
1260}
1261
1262// Our mbedtls currently has a no-op set_tls_version_max() implementation,
1263// so we can't set mismatched client and server TLS versions.
1264// For now, just test this for OPENSSL which is full-featured.
1265#ifdef USE_OPENSSL
1266TEST_F(ProtoUnitTest, BaseSingleThreadTlsVersionMismatch)
1267{
1268 int ret = test(1, false, true);
1269 EXPECT_NE(ret, 0);
1270}
1271#endif
1272
1273#ifdef USE_TLS_CRYPT_V2
1274TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithEmbeddedServerkey)
1275{
1276 int ret = test_retry(1, N_RETRIES, false, false, "tls-crypt-v2-client-with-serverkey.key");
1277 EXPECT_EQ(ret, 0);
1278}
1279
1280TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithMissingEmbeddedServerkey)
1281{
1282 int ret = test(1, false, false, "tls-crypt-v2-client-with-missing-serverkey.key");
1283 EXPECT_NE(ret, 0);
1284}
1285
1286TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithTlsAuthAlsoActive)
1287{
1288 int ret = test_retry(1, N_RETRIES, false, false, "tls-crypt-v2-client-with-serverkey.key", true);
1289 EXPECT_EQ(ret, 0);
1290}
1291#endif
1292
1293TEST_F(ProtoUnitTest, BaseMultipleThread)
1294{
1295 unsigned int num_threads = std::thread::hardware_concurrency();
1296#if defined(PROTO_N_THREADS) && PROTO_N_THREADS >= 1
1297 num_threads = PROTO_N_THREADS;
1298#endif
1299
1300 std::vector<std::thread> running_threads{};
1301 std::vector<int> results(num_threads, -777);
1302
1303 for (unsigned int i = 0; i < num_threads; ++i)
1304 {
1305 running_threads.emplace_back([i, &results]()
1306 {
1307 /* Use ekm on odd threads */
1308 const bool use_ekm = openvpn::SSLLib::SSLAPI::support_key_material_export() && (i % 2 == 0);
1309 results[i] = test_retry(static_cast<int>(i), N_RETRIES, use_ekm); });
1310 }
1311 for (unsigned int i = 0; i < num_threads; ++i)
1312 {
1313 running_threads[i].join();
1314 }
1315
1316
1317 // expect 1 for all threads
1318 const std::vector<int> expected_results(num_threads, 0);
1319
1320 EXPECT_THAT(expected_results, ::testing::ContainerEq(results));
1321}
1322
1323TEST(Proto, IvCiphersAead)
1324{
1325 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, true, false);
1326
1327 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1328
1329 auto infostring = protoConf.peer_info_string(false);
1330
1331 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1332 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1333
1334
1335 std::string expectedstr{"IV_CIPHERS=AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1336 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1337 expectedstr += ":CHACHA20-POLY1305";
1338
1339 EXPECT_EQ(ivciphers, expectedstr);
1340}
1341
1342TEST(Proto, IvCiphersNonPreferred)
1343{
1344 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, false, false);
1345
1346 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1347
1348 auto infostring = protoConf.peer_info_string(true);
1349
1350 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1351 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1352
1353
1354 std::string expectedstr{"IV_CIPHERS=AES-128-CBC:AES-192-CBC:AES-256-CBC:AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1355 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1356 expectedstr += ":CHACHA20-POLY1305";
1357
1358 EXPECT_EQ(ivciphers, expectedstr);
1359}
1360
1361TEST(Proto, IvCiphersLegacy)
1362{
1363
1364 /* Need to a whole lot of things to enable legacy provider/OpenSSL context */
1365 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1366 EXPECT_TRUE(config);
1367
1368 StrongRandomAPI::Ptr rng(new SSLLib::RandomAPI());
1369 config->set_rng(rng);
1370
1371 config->set_mode(Mode(Mode::CLIENT));
1373 config->set_local_cert_enabled(false);
1374 config->enable_legacy_algorithms(true);
1375
1376 auto factory_client = config->new_factory();
1377 EXPECT_TRUE(factory_client);
1378
1379 auto client = factory_client->ssl();
1380 auto libctx = factory_client->libctx();
1381
1382
1383 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(libctx, false, true);
1384
1385 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1386
1387 auto infostring = protoConf.peer_info_string(false);
1388
1389 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1390 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1391
1392
1393
1394 std::string expectedstr{"IV_CIPHERS=none:AES-128-CBC:AES-192-CBC:AES-256-CBC:DES-CBC:DES-EDE3-CBC"};
1395
1396 if (SSLLib::CryptoAPI::CipherContext::is_supported(libctx, openvpn::CryptoAlgs::BF_CBC))
1397 expectedstr += ":BF-CBC";
1398
1399 expectedstr += ":AES-128-GCM:AES-192-GCM:AES-256-GCM";
1400
1401 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1402 expectedstr += ":CHACHA20-POLY1305";
1403
1404 EXPECT_EQ(ivciphers, expectedstr);
1405}
1406
1407TEST(Proto, ControlmessageInvalidchar)
1408{
1409 std::string valid_auth_fail{"AUTH_FAILED: go away"};
1410 std::string valid_auth_fail_newline_end{"AUTH_FAILED: go away\n"};
1411 std::string invalid_auth_fail{"AUTH_FAILED: go\n away\n"};
1412 std::string lot_of_whitespace{"AUTH_FAILED: a lot of white space\n\n\r\n\r\n\r\n"};
1413 std::string only_whitespace{"\n\n\r\n\r\n\r\n"};
1414 std::string empty{""};
1415
1416 BufferAllocated valid_auth_fail_buf{reinterpret_cast<const unsigned char *>(valid_auth_fail.c_str()), valid_auth_fail.size(), BufAllocFlags::GROW};
1417 BufferAllocated valid_auth_fail_newline_end_buf{reinterpret_cast<const unsigned char *>(valid_auth_fail_newline_end.c_str()), valid_auth_fail_newline_end.size(), BufAllocFlags::GROW};
1418 BufferAllocated invalid_auth_fail_buf{reinterpret_cast<const unsigned char *>(invalid_auth_fail.c_str()), invalid_auth_fail.size(), BufAllocFlags::GROW};
1419 BufferAllocated lot_of_whitespace_buf{reinterpret_cast<const unsigned char *>(lot_of_whitespace.c_str()), lot_of_whitespace.size(), BufAllocFlags::GROW};
1420 BufferAllocated only_whitespace_buf{reinterpret_cast<const unsigned char *>(only_whitespace.c_str()), only_whitespace.size(), BufAllocFlags::GROW};
1421 BufferAllocated empty_buf{reinterpret_cast<const unsigned char *>(empty.c_str()), empty.size(), BufAllocFlags::GROW};
1422
1423 auto msg = ProtoContext::read_control_string<std::string>(valid_auth_fail_buf);
1424 EXPECT_EQ(msg, valid_auth_fail);
1426
1427 auto msg2 = ProtoContext::read_control_string<std::string>(valid_auth_fail_newline_end_buf);
1428 EXPECT_EQ(msg2, valid_auth_fail);
1430
1431 auto msg3 = ProtoContext::read_control_string<std::string>(invalid_auth_fail_buf);
1432 EXPECT_EQ(msg3, "AUTH_FAILED: go\n away");
1433 EXPECT_FALSE(Unicode::is_valid_utf8(msg3, Unicode::UTF8_NO_CTRL));
1434
1435 auto msg4 = ProtoContext::read_control_string<std::string>(lot_of_whitespace_buf);
1436 EXPECT_EQ(msg4, "AUTH_FAILED: a lot of white space");
1438
1439 auto msg5 = ProtoContext::read_control_string<std::string>(only_whitespace_buf);
1440 EXPECT_EQ(msg5, "");
1442
1443 auto msg6 = ProtoContext::read_control_string<std::string>(empty_buf);
1444 EXPECT_EQ(msg6, "");
1446}
1447
1454
1456{
1457 public:
1459 {
1460 events.push_back(event);
1461 }
1462
1463 std::vector<openvpn::ClientEvent::Base::Ptr> events;
1464};
1465
1466TEST(Proto, ClientProtoCheckCcMsg)
1467{
1468 asio::io_context io_context;
1469 ClientRandomAPI::Ptr rng_cli(new ClientRandomAPI());
1470 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1471 MySessionStats::Ptr cli_stats(new MySessionStats);
1472 Time time;
1473
1475 /* keep a reference to the right class to avoid repeated casted */
1476 EventQueueVector *eqv = dynamic_cast<EventQueueVector *>(eqv_ptr.get());
1477 /* check that the cast worked */
1478 ASSERT_TRUE(eqv);
1479
1480 MockCallback mockCB;
1483 frame,
1484 rng_cli,
1485 std::move(cli_stats),
1486 time);
1487 clisessconf.cli_events = std::move(eqv_ptr);
1488 openvpn::ClientProto::Session::Ptr clisession = new ClientProto::Session{io_context, clisessconf, &mockCB};
1489
1490 clisession->validate_and_post_cc_msg("valid message");
1491
1492
1493 EXPECT_TRUE(eqv->events.empty());
1494
1495 clisession->validate_and_post_cc_msg("invalid\nmessage");
1496 EXPECT_EQ(eqv->events.size(), 1);
1497 auto ev = eqv->events.back();
1498 auto uf = dynamic_cast<openvpn::ClientEvent::UnsupportedFeature *>(ev.get());
1499 /* check that the cast worked */
1500 ASSERT_TRUE(uf);
1501 EXPECT_EQ(uf->name, "Invalid chars in control message");
1502 EXPECT_EQ(uf->reason, "Control channel message with invalid characters not allowed to be send with post_cc_msg");
1503}
Time::Duration operator()() const
Time::Duration drought
std::string name
DroughtMeasure(const std::string &name_arg, TimePtr now_arg)
OPENVPN_SIMPLE_EXCEPTION(drought_limit_exceeded)
void add_event(openvpn::ClientEvent::Base::Ptr event) override
std::vector< openvpn::ClientEvent::Base::Ptr > events
void client_proto_terminate()
count_t errors[Error::N_ERRORS]
Definition test_comp.cpp:89
void error(const size_t err_type, const std::string *text=nullptr) override
count_t get_error_count(const Error::Type type) const
void show_error_counts() const
BufferPtr recv()
void xfer(T1 &a, T2 &b)
std::deque< BufferPtr > wire
unsigned int rand(const unsigned int prob)
unsigned int reorder_prob
NoisyWire(const std::string &title_arg, TimePtr now_arg, RandomAPI &rand_arg, const unsigned int reorder_prob_arg, const unsigned int drop_prob_arg, const unsigned int corrupt_prob_arg)
RandomAPI & random
std::string title
unsigned int corrupt_prob
unsigned int drop_prob
void SetUp() override
void TearDown() override
TestProtoClient(const ProtoContext::ProtoConfig::Ptr &config, const SessionStats::Ptr &stats)
void client_auth(Buffer &buf) override
void server_auth(const std::string &username, const SafeString &password, const std::string &peer_info, const AuthCert::Ptr &auth_cert) override
TestProtoServer(const ProtoContext::ProtoConfig::Ptr &config, const SessionStats::Ptr &stats)
OPENVPN_SIMPLE_EXCEPTION(auth_failed)
void check_invalidated()
TestProto(const ProtoContext::ProtoConfig::Ptr &config, const SessionStats::Ptr &stats)
void control_recv(BufferPtr &&app_bp) override
DroughtMeasure data_drought
void modmsg(BufferPtr &buf)
void data_decrypt(const ProtoContext::PacketType &type, BufferAllocated &in_out)
void control_send(BufferPtr &&app_bp)
void data_encrypt(BufferAllocated &in_out)
void initial_app_send(const char *msg)
const char * progress() const
void control_send(BufferAllocated &&app_buf)
ProtoContext proto_context
void reset()
void active(bool primary) override
Called when KeyContext transitions to ACTIVE state.
size_t app_bytes() const
size_t n_control_recv() const
void disable_xmit()
DroughtMeasure control_drought
Frame::Ptr frame
BufferPtr data_encrypt_string(const char *str)
size_t n_control_send() const
OPENVPN_EXCEPTION(session_invalidated)
size_t n_control_recv_
void app_send_templ_init(const char *msg)
size_t n_control_send_
size_t app_bytes_
void control_net_send(const Buffer &net_buf) override
bool do_housekeeping()
void finalize()
bool supports_epoch_data() override
BufferPtr templ
char progress_[11]
size_t data_bytes() const
void app_send_templ()
size_t data_bytes_
size_t net_bytes() const
size_t net_bytes_
void copy_progress(Buffer &buf)
std::deque< BufferPtr > net_out
bool disable_xmit_
size_t size() const
Returns the size of the buffer in T objects.
Definition buffer.hpp:1241
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1447
bool empty() const
Returns true if the buffer is empty.
Definition buffer.hpp:1235
size_t prepare(const unsigned int context, Buffer &buf) const
Definition frame.hpp:263
const Time::Duration & slowest_handshake()
Definition proto.hpp:4376
const Time & now() const
Definition proto.hpp:4477
void flush(const bool control_channel)
Definition proto.hpp:4197
void control_send(BufferPtr &&app_bp)
Definition proto.hpp:4253
void data_encrypt(BufferAllocated &in_out)
Definition proto.hpp:4291
static void write_auth_string(const S &str, Buffer &buf)
Definition proto.hpp:1541
bool is_server() const
Definition proto.hpp:4501
bool data_decrypt(const PacketType &type, BufferAllocated &in_out)
Definition proto.hpp:4301
Error::Type invalidation_reason() const
Definition proto.hpp:4388
unsigned int negotiations() const
Definition proto.hpp:4370
Time next_housekeeping() const
Definition proto.hpp:4235
bool invalidated() const
Definition proto.hpp:4382
void reset(const ProtoSessionID cookie_psid=ProtoSessionID())
Resets ProtoContext *this to it's initial state.
Definition proto.hpp:4042
void start(const ProtoSessionID cookie_psid=ProtoSessionID())
Initialize the state machine and start protocol negotiation.
Definition proto.hpp:4171
const ProtoConfig & conf() const
Definition proto.hpp:4521
void swap(RCPtr &rhs) noexcept
swaps the contents of two RCPtr<T>
Definition rc.hpp:311
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
Definition rc.hpp:321
Abstract base class for random number generators.
Definition randapi.hpp:39
T randrange(const T end)
Return a uniformly distributed random number in the range [0, end)
Definition randapi.hpp:117
static Ptr Create(ArgsT &&...args)
Creates a new instance of RcEnable with the given arguments.
Definition make_rc.hpp:43
A string-like type that clears the buffer contents on delete.
Definition safestr.hpp:27
void parse(const std::string &key_text)
void extract_wkc(BufferAllocated &wkc_out) const
void extract_key(OpenVPNStaticKey &tls_key)
void extract_key(OpenVPNStaticKey &tls_key)
void parse(const std::string &key_text)
T raw() const
Definition time.hpp:404
static TimeType infinite()
Definition time.hpp:254
bool defined() const
Definition time.hpp:280
static void set_log_level(int level)
set the log level for all loggigng
Definition logger.hpp:174
void work(openvpn_io::io_context &io_context, ThreadCommon &tc, MyRunContext &runctx, const unsigned int unit)
constexpr BufferFlags GROW(1U<< 2)
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
constexpr BufferFlags NO_FLAGS(0U)
no flags set
Type lookup(const std::string &name)
const char * name(const size_t type)
Definition error.hpp:117
@ HANDSHAKE_TIMEOUT
Definition error.hpp:60
bool is_valid_utf8(const STRING &str, const size_t max_len_flags=0)
Definition unicode.hpp:75
std::string read_text(const std::string &filename, const std::uint64_t max_size=0)
Definition file.hpp:127
long long count_t
Definition count.hpp:16
RCPtr< BufferAllocatedRc > BufferPtr
Definition buffer.hpp:1896
ProtoContext::ProtoConfig::Ptr proto_context_config
Definition cliproto.hpp:126
unsigned int mssfix
Definition mssparms.hpp:71
os<< "Session Name: "<< tbc-> session_name<< '\n';os<< "Layer: "<< tbc-> layer str()<< '\n'
std::string ret
static const char config[]
#define TLS_TIMEOUT_CLIENT
int test_retry(const int thread_num, const int n_retries, bool use_tls_ekm, bool tls_version_mismatch=false, const std::string &tls_crypt_v2_key_fn="", bool use_tls_auth_with_tls_crypt_v2=false)
#define TLS_TIMEOUT_SERVER
#define PROTO_DIGEST
static auto create_client_proto_context(ClientSSLAPI::Config::Ptr cc, Frame::Ptr frame, ClientRandomAPI::Ptr rng, MySessionStats::Ptr cli_stats, Time &time, const std::string &tls_crypt_v2_key_fn="")
TEST_F(ProtoUnitTest, BaseSingleThreadTlsEkm)
#define TLS_VER_MIN
#define N_RETRIES
#define COMP_METH
#define ITER
TEST(Proto, IvCiphersAead)
const char message[]
#define PROTO_CIPHER
#define SITER
#define RENEG
static auto create_client_ssl_config(Frame::Ptr frame, ClientRandomAPI::Ptr rng, bool tls_version_mismatch=false)
void test()
Definition test_rc.cpp:80
#define msg(flags,...)