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#if defined(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)
197
201
202#endif
203
204#if defined(USE_APPLE_SSL) || defined(USE_MBEDTLS_APPLE_HYBRID)
208#endif
209
210#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_SERVER)
214#include <mbedtls/debug.h>
215#endif
216
218
219using namespace openvpn;
220
221// server Crypto/SSL/Rand implementation
222#if defined(USE_MBEDTLS_SERVER)
223typedef MbedTLSCryptoAPI ServerCryptoAPI;
224typedef MbedTLSContext ServerSSLAPI;
225typedef MbedTLSRandom ServerRandomAPI;
226#elif defined(USE_OPENSSL_SERVER)
227typedef OpenSSLCryptoAPI ServerCryptoAPI;
228typedef OpenSSLContext ServerSSLAPI;
229typedef OpenSSLRandom ServerRandomAPI;
230#else
231#error No server SSL implementation defined
232#endif
233
234// client SSL implementation can be OpenSSL, Apple SSL, or MbedTLS
235#if defined(USE_MBEDTLS)
236#if defined(USE_MBEDTLS_APPLE_HYBRID)
237typedef AppleCryptoAPI ClientCryptoAPI;
238#else
239typedef MbedTLSCryptoAPI ClientCryptoAPI;
240#endif
241typedef MbedTLSContext ClientSSLAPI;
242typedef MbedTLSRandom ClientRandomAPI;
243#elif defined(USE_APPLE_SSL)
244typedef AppleCryptoAPI ClientCryptoAPI;
245typedef AppleSSLContext ClientSSLAPI;
246typedef AppleRandom ClientRandomAPI;
247#elif defined(USE_OPENSSL)
248typedef OpenSSLCryptoAPI ClientCryptoAPI;
249typedef OpenSSLContext ClientSSLAPI;
250typedef OpenSSLRandom ClientRandomAPI;
251#else
252#error No client SSL implementation defined
253#endif
254
255const char message[] = "Message _->_ 0000000000 It was a bright cold day in April, and the clocks\n"
256 "were striking thirteen. Winston Smith, his chin nuzzled\n"
257 "into his breast in an effort to escape the vile wind,\n"
258 "slipped quickly through the glass doors of Victory\n"
259 "Mansions, though not quickly enough to prevent a\n"
260 "swirl of gritty dust from entering along with him.\n"
261#ifdef LARGE_MESSAGE
262 "It was a bright cold day in April, and the clocks\n"
263 "were striking thirteen. Winston Smith, his chin nuzzled\n"
264 "into his breast in an effort to escape the vile wind,\n"
265 "slipped quickly through the glass doors of Victory\n"
266 "Mansions, though not quickly enough to prevent a\n"
267 "swirl of gritty dust from entering along with him.\n"
268 "It was a bright cold day in April, and the clocks\n"
269 "were striking thirteen. Winston Smith, his chin nuzzled\n"
270 "into his breast in an effort to escape the vile wind,\n"
271 "slipped quickly through the glass doors of Victory\n"
272 "Mansions, though not quickly enough to prevent a\n"
273 "swirl of gritty dust from entering along with him.\n"
274 "It was a bright cold day in April, and the clocks\n"
275 "were striking thirteen. Winston Smith, his chin nuzzled\n"
276 "into his breast in an effort to escape the vile wind,\n"
277 "slipped quickly through the glass doors of Victory\n"
278 "Mansions, though not quickly enough to prevent a\n"
279 "swirl of gritty dust from entering along with him.\n"
280 "It was a bright cold day in April, and the clocks\n"
281 "were striking thirteen. Winston Smith, his chin nuzzled\n"
282 "into his breast in an effort to escape the vile wind,\n"
283 "slipped quickly through the glass doors of Victory\n"
284 "Mansions, though not quickly enough to prevent a\n"
285 "swirl of gritty dust from entering along with him.\n"
286#endif
287 ;
288
289// A "Drought" measures the maximum period of time between
290// any two successive events. Used to measure worst-case
291// packet loss.
293{
294 public:
295 OPENVPN_SIMPLE_EXCEPTION(drought_limit_exceeded);
296
297 DroughtMeasure(const std::string &name_arg, TimePtr now_arg)
298 : now(now_arg), name(name_arg)
299 {
300 }
301
302 void event()
303 {
304 if (last_event.defined())
305 {
306 Time::Duration since_last = *now - last_event;
307 if (since_last > drought)
308 {
309 drought = since_last;
310#if defined(VERBOSE) || defined(DROUGHT_LIMIT)
311 {
312 const unsigned int r = drought.raw();
313#if defined(VERBOSE)
314 std::cout << "*** Drought " << name << " has reached " << r << std::endl;
315#endif
316#ifdef DROUGHT_LIMIT
317 if (r > DROUGHT_LIMIT)
318 throw drought_limit_exceeded();
319#endif
320 }
321#endif
322 }
323 }
324 last_event = *now;
325 }
326
327 Time::Duration operator()() const
328 {
329 return drought;
330 }
331
332 private:
335 Time::Duration drought;
336 std::string name;
337};
338
339// test the OpenVPN protocol implementation in ProtoContext
341{
342 /* Callback methods that are not used */
343 void active(bool primary) override
344 {
345 }
346
347 bool supports_epoch_data() override
348 {
349 return true;
350 }
351
352 public:
353 OPENVPN_EXCEPTION(session_invalidated);
354
356 const SessionStats::Ptr &stats)
357 : proto_context(this, config, stats),
358 control_drought("control", config->now),
359 data_drought("data", config->now),
361 {
362 // zero progress value
363 std::memset(progress_, 0, 11);
364 }
365
372
373 void initial_app_send(const char *msg)
374 {
376 const size_t msglen = std::strlen(msg) + 1;
377 BufferAllocated app_buf((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
378 copy_progress(app_buf);
379 control_send(std::move(app_buf));
380 proto_context.flush(true);
381 }
382
383 void app_send_templ_init(const char *msg)
384 {
386 const size_t msglen = std::strlen(msg) + 1;
387 templ = BufferAllocatedRc::Create((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
388 proto_context.flush(true);
389 }
390
392 {
393#if !FEEDBACK
394 if (bool(iteration++ & 1) == is_server())
395 {
396 modmsg(templ);
397 BufferAllocated app_buf(*templ);
398 control_send(std::move(app_buf));
399 flush(true);
401 }
402#endif
403 }
404
406 {
408 {
410 return true;
411 }
412 else
413 return false;
414 }
415
416 void control_send(BufferPtr &&app_bp)
417 {
418 app_bytes_ += app_bp->size();
419 proto_context.control_send(std::move(app_bp));
420 }
421
423 {
424 app_bytes_ += app_buf.size();
425 proto_context.control_send(std::move(app_buf));
426 }
427
429 {
432 bp->write((unsigned char *)str, std::strlen(str));
433 data_encrypt(*bp);
434 return bp;
435 }
436
438 {
440 }
441
443 {
444 proto_context.data_decrypt(type, in_out);
445 if (in_out.size())
446 {
447 data_bytes_ += in_out.size();
449 }
450 }
451
452 size_t net_bytes() const
453 {
454 return net_bytes_;
455 }
456 size_t app_bytes() const
457 {
458 return app_bytes_;
459 }
460 size_t data_bytes() const
461 {
462 return data_bytes_;
463 }
464 size_t n_control_recv() const
465 {
466 return n_control_recv_;
467 }
468 size_t n_control_send() const
469 {
470 return n_control_send_;
471 }
472
473 const char *progress() const
474 {
475 return progress_;
476 }
477
478 void finalize()
479 {
482 }
483
485 {
487 throw session_invalidated(Error::name(proto_context.invalidation_reason()));
488 }
489
491 {
492 disable_xmit_ = true;
493 }
494
496
497 std::deque<BufferPtr> net_out;
498
501
502 private:
503 void control_net_send(const Buffer &net_buf) override
504 {
505 if (disable_xmit_)
506 return;
507 net_bytes_ += net_buf.size();
509 }
510
511 void control_recv(BufferPtr &&app_bp) override
512 {
514 work.swap(app_bp);
515 if (work->size() >= 23)
516 std::memcpy(progress_, work->data() + 13, 10);
517
518#ifdef VERBOSE
519 {
520 const ssize_t trunc = 64;
521 const std::string show((char *)work->data(), trunc);
522 std::cout << now().raw() << " " << mode().str() << " " << show << std::endl;
523 }
524#endif
525#if FEEDBACK
526 modmsg(work);
527 control_send(std::move(work));
528#endif
531 }
532
534 {
535 if (progress_[0]) // make sure progress was initialized
536 std::memcpy(buf.data() + 13, progress_, 10);
537 }
538
539 void modmsg(BufferPtr &buf)
540 {
541 char *msg = (char *)buf->data();
543 {
544 msg[8] = 'S';
545 msg[11] = 'C';
546 }
547 else
548 {
549 msg[8] = 'C';
550 msg[11] = 'S';
551 }
552
553 // increment embedded number
554 for (int i = 22; i >= 13; i--)
555 {
556 if (msg[i] != '9')
557 {
558 msg[i]++;
559 break;
560 }
561 else
562 msg[i] = '0';
563 }
564 }
565
567 size_t app_bytes_ = 0;
568 size_t net_bytes_ = 0;
569 size_t data_bytes_ = 0;
570 size_t n_control_send_ = 0;
571 size_t n_control_recv_ = 0;
573#if !FEEDBACK
574 size_t iteration = 0;
575#endif
576 char progress_[11];
577 bool disable_xmit_ = false;
578};
579
581{
583
584 public:
586 const SessionStats::Ptr &stats)
587 : TestProto(config, stats)
588 {
589 }
590
591 private:
592 void client_auth(Buffer &buf) override
593 {
594 const std::string username("foo");
595 const std::string password("bar");
596 ProtoContext::write_auth_string(username, buf);
597 ProtoContext::write_auth_string(password, buf);
598 }
599};
600
602{
603
604 public:
605 void start()
606 {
608 }
609
611
612
614 const SessionStats::Ptr &stats)
615 : TestProto(config, stats)
616 {
617 }
618
619 private:
620 void server_auth(const std::string &username,
621 const SafeString &password,
622 const std::string &peer_info,
623 const AuthCert::Ptr &auth_cert) override
624 {
625#ifdef VERBOSE
626 std::cout << "**** AUTHENTICATE " << username << '/' << password << " PEER INFO:" << std::endl;
627 std::cout << peer_info;
628#endif
629 if (username != "foo" || password != "bar")
630 throw auth_failed();
631 }
632};
633
634// Simulate a noisy transmission channel where packets can be dropped,
635// reordered, or corrupted.
637{
638 public:
639 NoisyWire(const std::string title_arg,
640 TimePtr now_arg,
641 RandomAPI &rand_arg,
642 const unsigned int reorder_prob_arg,
643 const unsigned int drop_prob_arg,
644 const unsigned int corrupt_prob_arg)
645 : title(title_arg),
646#ifdef VERBOSE
647 now(now_arg),
648#endif
649 random(rand_arg),
650 reorder_prob(reorder_prob_arg),
651 drop_prob(drop_prob_arg),
652 corrupt_prob(corrupt_prob_arg)
653 {
654 }
655
656 template <typename T1, typename T2>
657 void xfer(T1 &a, T2 &b)
658 {
659 // check for errors
660 a.check_invalidated();
661 b.check_invalidated();
662
663 // need to retransmit?
664 if (a.do_housekeeping())
665 {
666#ifdef VERBOSE
667 std::cout << now->raw() << " " << title << " Housekeeping" << std::endl;
668#endif
669 }
670
671 // queue a control channel packet
672 a.app_send_templ();
673
674 // queue a data channel packet
675 if (a.proto_context.data_channel_ready())
676 {
677 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...");
678 wire.push_back(bp);
679 }
680
681 // transfer network packets from A -> wire
682 while (!a.net_out.empty())
683 {
684 BufferPtr bp = a.net_out.front();
685#ifdef VERBOSE
686 std::cout << now->raw() << " " << title << " " << a.dump_packet(*bp) << std::endl;
687#endif
688 a.net_out.pop_front();
689 wire.push_back(bp);
690 }
691
692 // transfer network packets from wire -> B
693 while (true)
694 {
695 BufferPtr bp = recv();
696 if (!bp)
697 break;
698 typename ProtoContext::PacketType pt = b.proto_context.packet_type(*bp);
699 if (pt.is_control())
700 {
701#ifdef VERBOSE
702 if (!b.control_net_validate(pt, *bp)) // not strictly necessary since control_net_recv will also validate
703 std::cout << now->raw() << " " << title << " CONTROL PACKET VALIDATION FAILED" << std::endl;
704#endif
705 b.proto_context.control_net_recv(pt, std::move(bp));
706 }
707 else if (pt.is_data())
708 {
709 try
710 {
711 b.data_decrypt(pt, *bp);
712#ifdef VERBOSE
713 if (bp->size())
714 {
715 const std::string show((char *)bp->data(), std::min(bp->size(), size_t(40)));
716 std::cout << now->raw() << " " << title << " DATA CHANNEL DECRYPT: " << show << std::endl;
717 }
718#endif
719 }
720 catch ([[maybe_unused]] const std::exception &e)
721 {
722#ifdef VERBOSE
723 std::cout << now->raw() << " " << title << " Exception on data channel decrypt: " << e.what() << std::endl;
724#endif
725 }
726 }
727 else
728 {
729#ifdef VERBOSE
730 std::cout << now->raw() << " " << title << " KEY_STATE_ERROR" << std::endl;
731#endif
732 b.proto_context.stat().error(Error::KEY_STATE_ERROR);
733 }
734
735#ifdef SIMULATE_UDP_AMPLIFY_ATTACK
736 if (b.proto_context.is_state_client_wait_reset_ack())
737 {
738 b.disable_xmit();
739#ifdef VERBOSE
740 std::cout << now->raw() << " " << title << " SIMULATE_UDP_AMPLIFY_ATTACK disable client xmit" << std::endl;
741#endif
742 }
743#endif
744 }
745 b.proto_context.flush(true);
746 }
747
748 private:
750 {
751#ifdef SIMULATE_OOO
752 // simulate packets being received out of order
753 if (wire.size() >= 2 && !rand(reorder_prob))
754 {
755 const size_t i = random.randrange(wire.size() - 1) + 1;
756#ifdef VERBOSE
757 std::cout << now->raw() << " " << title << " Simulating packet reordering " << i << " -> 0" << std::endl;
758#endif
759 std::swap(wire[0], wire[i]);
760 }
761#endif
762
763 if (wire.size())
764 {
765 BufferPtr bp = wire.front();
766 wire.pop_front();
767
768#ifdef VERBOSE
769 std::cout << now->raw() << " " << title << " Received packet, size=" << bp->size() << std::endl;
770#endif
771
772#ifdef SIMULATE_DROPPED
773 // simulate dropped packet
774 if (!rand(drop_prob))
775 {
776#ifdef VERBOSE
777 std::cout << now->raw() << " " << title << " Simulating a dropped packet" << std::endl;
778#endif
779 return BufferPtr();
780 }
781#endif
782
783#ifdef SIMULATE_CORRUPTED
784 // simulate corrupted packet
785 if (bp->size() && !rand(corrupt_prob))
786 {
787#ifdef VERBOSE
788 std::cout << now->raw() << " " << title << " Simulating a corrupted packet" << std::endl;
789#endif
790 const size_t pos = random.randrange(bp->size());
791 const unsigned char value = random.randrange(std::numeric_limits<unsigned char>::max());
792 (*bp)[pos] = value;
793 }
794#endif
795 return bp;
796 }
797
798 return BufferPtr();
799 }
800
801 unsigned int rand(const unsigned int prob)
802 {
803 if (prob)
804 return random.randrange(prob);
805 else
806 return 1;
807 }
808
809 std::string title;
810#ifdef VERBOSE
811 TimePtr now;
812#endif
814 unsigned int reorder_prob;
815 unsigned int drop_prob;
816 unsigned int corrupt_prob;
817 std::deque<BufferPtr> wire;
818};
819
820class MySessionStats : public SessionStats
821{
822 public:
824
826 {
827 std::memset(errors, 0, sizeof(errors));
828 }
829
830 void error(const size_t err_type, const std::string *text = nullptr) override
831 {
832 if (err_type < Error::N_ERRORS)
833 ++errors[err_type];
834 }
835
837 {
838 if (type < Error::N_ERRORS)
839 return errors[type];
840 else
841 return 0;
842 }
843
844 void show_error_counts() const
845 {
846 for (size_t i = 0; i < Error::N_ERRORS; ++i)
847 {
848 count_t c = errors[i];
849 if (c)
850 std::cerr << Error::name(i) << " : " << c << std::endl;
851 }
852 }
853
854 private:
856};
857
862static auto create_client_ssl_config(Frame::Ptr frame, ClientRandomAPI::Ptr rng, bool tls_version_mismatch = false)
863{
864 const std::string client_crt = read_text(TEST_KEYCERT_DIR "client.crt");
865 const std::string client_key = read_text(TEST_KEYCERT_DIR "client.key");
866 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
867
868 // client config
869 ClientSSLAPI::Config::Ptr cc(new ClientSSLAPI::Config());
870 cc->set_mode(Mode(Mode::CLIENT));
871 cc->set_frame(frame);
872 cc->set_rng(rng);
873#ifdef USE_APPLE_SSL
874 cc->load_identity("etest");
875#else
876 cc->load_ca(ca_crt, true);
877 cc->load_cert(client_crt);
878 cc->load_private_key(client_key);
879#endif
880 if (tls_version_mismatch)
881 cc->set_tls_version_max(TLSVersion::Type::V1_2);
882 else
883 cc->set_tls_version_min(TLS_VER_MIN);
884#ifdef VERBOSE
885 cc->set_debug_level(1);
886#endif
887 return cc;
888}
889
890static 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 = "")
891
892{
893 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
894 const std::string tls_crypt_v2_client_key = tls_crypt_v2_key_fn.empty()
895 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-client.key")
896 : read_text(TEST_KEYCERT_DIR + tls_crypt_v2_key_fn);
897
898 // client ProtoContext config
899 typedef ProtoContext ClientProtoContext;
900 ClientProtoContext::ProtoConfig::Ptr cp(new ClientProtoContext::ProtoConfig);
901 cp->ssl_factory = cc->new_factory();
902 CryptoAlgs::allow_default_dc_algs<ClientCryptoAPI>(cp->ssl_factory->libctx(), false, false);
903 cp->dc.set_factory(new CryptoDCSelect<ClientCryptoAPI>(cp->ssl_factory->libctx(), frame, cli_stats, rng));
904 cp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ClientCryptoAPI>());
905 cp->frame = std::move(frame);
906 cp->now = &time;
907 cp->rng = rng;
908 cp->prng = rng;
909 cp->protocol = Protocol(Protocol::UDPv4);
910 cp->layer = Layer(Layer::OSI_LAYER_3);
911#ifdef PROTOv2
912 cp->enable_op32 = true;
913 cp->remote_peer_id = 100;
914#endif
915 cp->comp_ctx = CompressContext(COMP_METH, false);
916 cp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
917 cp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
918
919#ifdef USE_TLS_AUTH
920 cp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ClientCryptoAPI>());
921 cp->tls_auth_key.parse(tls_auth_key);
922 cp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
923 cp->key_direction = 0;
924#endif
925#ifdef USE_TLS_CRYPT
926 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
927 cp->tls_crypt_key.parse(tls_auth_key);
928 cp->set_tls_crypt_algs();
929 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
930#endif
931#ifdef USE_TLS_CRYPT_V2
932 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
933 cp->set_tls_crypt_algs();
934 {
935 TLSCryptV2ClientKey tls_crypt_v2_key(cp->tls_crypt_context);
936 tls_crypt_v2_key.parse(tls_crypt_v2_client_key);
937 tls_crypt_v2_key.extract_key(cp->tls_crypt_key);
938 tls_crypt_v2_key.extract_wkc(cp->wkc);
939 }
940 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
941#endif
942#if defined(HANDSHAKE_WINDOW)
943 cp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
944#elif SITER > 1
945 cp->handshake_window = Time::Duration::seconds(30);
946#else
947 cp->handshake_window = Time::Duration::seconds(18); // will cause a small number of handshake failures
948#endif
949#ifdef BECOME_PRIMARY_CLIENT
950 cp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_CLIENT);
951#else
952 cp->become_primary = cp->handshake_window;
953#endif
954 cp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_CLIENT);
955#if defined(CLIENT_NO_RENEG)
956 cp->renegotiate = Time::Duration::infinite();
957#else
958 cp->renegotiate = Time::Duration::seconds(RENEG);
959#endif
960 cp->expire = cp->renegotiate + cp->renegotiate;
961 cp->keepalive_ping = Time::Duration::seconds(5);
962 cp->keepalive_timeout = Time::Duration::seconds(60);
963 cp->keepalive_timeout_early = cp->keepalive_timeout;
964
965#ifdef VERBOSE
966 std::cout << "CLIENT OPTIONS: " << cp->options_string() << std::endl;
967 std::cout << "CLIENT PEER INFO:" << std::endl;
968 std::cout << cp->peer_info_string();
969#endif
970 return cp;
971}
972
973// execute the unit test in one thread
974int test(const int thread_num,
975 bool use_tls_ekm,
976 bool tls_version_mismatch,
977 const std::string &tls_crypt_v2_key_fn = "",
978 bool use_tls_auth_with_tls_crypt_v2 = false)
979{
980 try
981 {
982 // frame
983 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
984
985 // RNG
986 ClientRandomAPI::Ptr prng_cli(new ClientRandomAPI());
987 ServerRandomAPI::Ptr prng_serv(new ServerRandomAPI());
988 MTRand rng_noncrypto;
989
990 // init simulated time
991 Time time;
992 const Time::Duration time_step = Time::Duration::binary_ms(100);
993
994 // config files
995 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
996 const std::string server_crt = read_text(TEST_KEYCERT_DIR "server.crt");
997 const std::string server_key = read_text(TEST_KEYCERT_DIR "server.key");
998 const std::string dh_pem = read_text(TEST_KEYCERT_DIR "dh.pem");
999 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
1000 const std::string tls_crypt_v2_server_key = tls_crypt_v2_key_fn.empty()
1001 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-server.key")
1002 : "";
1003
1004 // client config
1005 ClientSSLAPI::Config::Ptr cc = create_client_ssl_config(frame, prng_cli, tls_version_mismatch);
1006 MySessionStats::Ptr cli_stats(new MySessionStats);
1007
1008 auto cp = create_client_proto_context(std::move(cc), frame, prng_cli, cli_stats, time, tls_crypt_v2_key_fn);
1009 if (use_tls_ekm)
1010 cp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1011
1012 // server config
1013 MySessionStats::Ptr serv_stats(new MySessionStats);
1014
1015 ServerSSLAPI::Config::Ptr sc(new ClientSSLAPI::Config());
1016 sc->set_mode(Mode(Mode::SERVER));
1017 sc->set_frame(frame);
1018 sc->set_rng(prng_serv);
1019 sc->load_ca(ca_crt, true);
1020 sc->load_cert(server_crt);
1021 sc->load_private_key(server_key);
1022 sc->load_dh(dh_pem);
1023 sc->set_tls_version_min(tls_version_mismatch ? TLSVersion::Type::V1_3 : TLS_VER_MIN);
1024#ifdef VERBOSE
1025 sc->set_debug_level(1);
1026#endif
1027
1028 // server ProtoContext config
1029 typedef ProtoContext ServerProtoContext;
1030 ServerProtoContext::ProtoConfig::Ptr sp(new ServerProtoContext::ProtoConfig);
1031 sp->ssl_factory = sc->new_factory();
1032 sp->dc.set_factory(new CryptoDCSelect<ServerCryptoAPI>(sp->ssl_factory->libctx(), frame, serv_stats, prng_serv));
1033 sp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ServerCryptoAPI>());
1034 sp->frame = frame;
1035 sp->now = &time;
1036 sp->rng = prng_serv;
1037 sp->prng = prng_serv;
1038 sp->protocol = Protocol(Protocol::UDPv4);
1039 sp->layer = Layer(Layer::OSI_LAYER_3);
1040#ifdef PROTOv2
1041 sp->enable_op32 = true;
1042 sp->remote_peer_id = 101;
1043#endif
1044 sp->comp_ctx = CompressContext(COMP_METH, false);
1045 sp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
1046 sp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1047 if (use_tls_ekm)
1048 sp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1049#ifdef USE_TLS_AUTH
1050 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1051 sp->tls_auth_key.parse(tls_auth_key);
1052 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1053 sp->key_direction = 1;
1054#endif
1055#if defined(USE_TLS_CRYPT)
1056 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1057 sp->tls_crypt_key.parse(tls_auth_key);
1058 sp->set_tls_crypt_algs();
1059 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
1060#endif
1061#ifdef USE_TLS_CRYPT_V2
1062 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1063
1064 if (tls_crypt_v2_key_fn.empty())
1065 {
1066 TLSCryptV2ServerKey tls_crypt_v2_key;
1067 tls_crypt_v2_key.parse(tls_crypt_v2_server_key);
1068 tls_crypt_v2_key.extract_key(sp->tls_crypt_key);
1069 }
1070
1071 sp->set_tls_crypt_algs();
1072 sp->tls_crypt_metadata_factory.reset(new CryptoTLSCryptMetadataFactory());
1073 sp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
1074 sp->tls_crypt_v2_serverkey_id = !tls_crypt_v2_key_fn.empty();
1075 sp->tls_crypt_v2_serverkey_dir = TEST_KEYCERT_DIR;
1076
1077 if (use_tls_auth_with_tls_crypt_v2)
1078 {
1079 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1080 sp->tls_auth_key.parse(tls_auth_key);
1081 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1082 sp->key_direction = 1;
1083 }
1084#endif
1085#if defined(HANDSHAKE_WINDOW)
1086 sp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
1087#elif SITER > 1
1088 sp->handshake_window = Time::Duration::seconds(30);
1089#else
1090 sp->handshake_window = Time::Duration::seconds(17) + Time::Duration::binary_ms(512);
1091#endif
1092#ifdef BECOME_PRIMARY_SERVER
1093 sp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_SERVER);
1094#else
1095 sp->become_primary = sp->handshake_window;
1096#endif
1097 sp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_SERVER);
1098#if defined(SERVER_NO_RENEG)
1099 sp->renegotiate = Time::Duration::infinite();
1100#else
1101 // NOTE: if we don't add sp->handshake_window, both client and server reneg-sec (RENEG)
1102 // will be equal and will therefore occasionally collide. Such collisions can sometimes
1103 // produce this OpenSSL error:
1104 // OpenSSLContext::SSL::read_cleartext: BIO_read failed, cap=400 status=-1: error:140E0197:SSL routines:SSL_shutdown:shutdown while in init
1105 // The issue was introduced by this patch in OpenSSL:
1106 // https://github.com/openssl/openssl/commit/64193c8218540499984cd63cda41f3cd491f3f59
1107 sp->renegotiate = Time::Duration::seconds(RENEG) + sp->handshake_window;
1108#endif
1109 sp->expire = sp->renegotiate + sp->renegotiate;
1110 sp->keepalive_ping = Time::Duration::seconds(5);
1111 sp->keepalive_timeout = Time::Duration::seconds(60);
1112 sp->keepalive_timeout_early = Time::Duration::seconds(10);
1113
1114#ifdef VERBOSE
1115 std::cout << "SERVER OPTIONS: " << sp->options_string() << std::endl;
1116 std::cout << "SERVER PEER INFO:" << std::endl;
1117 std::cout << sp->peer_info_string();
1118#endif
1119
1120 TestProtoClient cli_proto(cp, cli_stats);
1121 TestProtoServer serv_proto(sp, serv_stats);
1122
1123 for (int i = 0; i < SITER; ++i)
1124 {
1125#ifdef VERBOSE
1126 std::cout << "***** SITER " << i << std::endl;
1127#endif
1128 cli_proto.reset();
1129 serv_proto.reset();
1130
1131 NoisyWire client_to_server("Client -> Server", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1132 NoisyWire server_to_client("Server -> Client", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1133
1134 int j = -1;
1135 try
1136 {
1137#if FEEDBACK
1138 // start feedback loop
1139 cli_proto.initial_app_send(message);
1140 serv_proto.start();
1141#else
1142 cli_proto.app_send_templ_init(message);
1143 serv_proto.app_send_templ_init(message);
1144#endif
1145
1146 // message loop
1147 for (j = 0; j < ITER; ++j)
1148 {
1149 client_to_server.xfer(cli_proto, serv_proto);
1150 server_to_client.xfer(serv_proto, cli_proto);
1151 time += time_step;
1152 }
1153 }
1154 catch (const std::exception &e)
1155 {
1156 std::cerr << "Exception[" << i << '/' << j << "]: " << e.what() << std::endl;
1157 return 1;
1158 }
1159 }
1160
1161 cli_proto.finalize();
1162 serv_proto.finalize();
1163
1164 const size_t ab = cli_proto.app_bytes() + serv_proto.app_bytes();
1165 const size_t nb = cli_proto.net_bytes() + serv_proto.net_bytes();
1166 const size_t db = cli_proto.data_bytes() + serv_proto.data_bytes();
1167
1168 std::cerr << "*** app bytes=" << ab
1169 << " net_bytes=" << nb
1170 << " data_bytes=" << db
1171 << " prog=" << cli_proto.progress() << '/' << serv_proto.progress()
1172#if !FEEDBACK
1173 << " CTRL=" << cli_proto.n_control_recv() << '/' << cli_proto.n_control_send() << '/' << serv_proto.n_control_recv() << '/' << serv_proto.n_control_send()
1174#endif
1175 << " D=" << cli_proto.control_drought().raw() << '/' << cli_proto.data_drought().raw() << '/' << serv_proto.control_drought().raw() << '/' << serv_proto.data_drought().raw()
1176 << " N=" << cli_proto.proto_context.negotiations() << '/' << serv_proto.proto_context.negotiations()
1177 << " SH=" << cli_proto.proto_context.slowest_handshake().raw() << '/' << serv_proto.proto_context.slowest_handshake().raw()
1178 << " HE=" << cli_stats->get_error_count(Error::HANDSHAKE_TIMEOUT) << '/' << serv_stats->get_error_count(Error::HANDSHAKE_TIMEOUT)
1179 << std::endl;
1180
1181#ifdef STATS
1182 std::cerr << "-------- CLIENT STATS --------" << std::endl;
1183 cli_stats->show_error_counts();
1184 std::cerr << "-------- SERVER STATS --------" << std::endl;
1185 serv_stats->show_error_counts();
1186#endif
1187#ifdef OPENVPN_MAX_DATALIMIT_BYTES
1188 std::cerr << "------------------------------" << std::endl;
1189 std::cerr << "MAX_DATALIMIT_BYTES=" << DataLimit::max_bytes() << std::endl;
1190#endif
1191 }
1192 catch (const std::exception &e)
1193 {
1194 std::cerr << "Exception: " << e.what() << std::endl;
1195 return 1;
1196 }
1197 return 0;
1198}
1199
1200int test_retry(const int thread_num,
1201 const int n_retries,
1202 bool use_tls_ekm,
1203 bool tls_version_mismatch = false,
1204 const std::string &tls_crypt_v2_key_fn = "",
1205 bool use_tls_auth_with_tls_crypt_v2 = false)
1206{
1207 int ret = 1;
1208 for (int i = 0; i < n_retries; ++i)
1209 {
1210 ret = test(thread_num, use_tls_ekm, tls_version_mismatch, tls_crypt_v2_key_fn, use_tls_auth_with_tls_crypt_v2);
1211 if (!ret)
1212 return 0;
1213 std::cout << "Retry " << (i + 1) << '/' << n_retries << std::endl;
1214 }
1215 std::cout << "Failed" << std::endl;
1216 return ret;
1217}
1218
1219class ProtoUnitTest : public testing::Test
1220{
1221 // Sets up the test fixture.
1222 void SetUp() override
1223 {
1224#if defined(USE_MBEDTLS)
1225 mbedtls_debug_set_threshold(1);
1226#endif
1227
1229
1230#ifdef PROTO_VERBOSE
1232#else
1234#endif
1235 }
1236
1237 // Tears down the test fixture.
1238 void TearDown() override
1239 {
1240#if defined(USE_MBEDTLS)
1241 mbedtls_debug_set_threshold(4);
1242#endif
1245 }
1246};
1247
1248TEST_F(ProtoUnitTest, base_single_thread_tls_ekm)
1249{
1250 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1251 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1252
1253 int ret = 0;
1254
1255 ret = test_retry(1, N_RETRIES, true);
1256
1257 EXPECT_EQ(ret, 0);
1258}
1259
1260TEST_F(ProtoUnitTest, base_single_thread_no_tls_ekm)
1261{
1262 int ret = 0;
1263
1264 ret = test_retry(1, N_RETRIES, false);
1265
1266 EXPECT_EQ(ret, 0);
1267}
1268
1269// Our mbedtls currently has a no-op set_tls_version_max() implementation,
1270// so we can't set mismatched client and server TLS versions.
1271// For now, just test this for OPENSSL which is full-featured.
1272#ifdef USE_OPENSSL
1273TEST_F(ProtoUnitTest, base_single_thread_tls_version_mismatch)
1274{
1275 int ret = test(1, false, true);
1276 EXPECT_NE(ret, 0);
1277}
1278#endif
1279
1280#ifdef USE_TLS_CRYPT_V2
1281TEST_F(ProtoUnitTest, base_single_thread_tls_crypt_v2_with_embedded_serverkey)
1282{
1283 int ret = test_retry(1, N_RETRIES, false, false, "tls-crypt-v2-client-with-serverkey.key");
1284 EXPECT_EQ(ret, 0);
1285}
1286
1287TEST_F(ProtoUnitTest, base_single_thread_tls_crypt_v2_with_missing_embedded_serverkey)
1288{
1289 int ret = test(1, false, false, "tls-crypt-v2-client-with-missing-serverkey.key");
1290 EXPECT_NE(ret, 0);
1291}
1292
1293TEST_F(ProtoUnitTest, base_single_thread_tls_crypt_v2_with_tls_auth_also_active)
1294{
1295 int ret = test_retry(1, N_RETRIES, false, false, "tls-crypt-v2-client-with-serverkey.key", true);
1296 EXPECT_EQ(ret, 0);
1297}
1298#endif
1299
1300TEST_F(ProtoUnitTest, base_multiple_thread)
1301{
1302 unsigned int num_threads = std::thread::hardware_concurrency();
1303#if defined(PROTO_N_THREADS) && PROTO_N_THREADS >= 1
1304 num_threads = PROTO_N_THREADS;
1305#endif
1306
1307 std::vector<std::thread> running_threads{};
1308 std::vector<int> results(num_threads, -777);
1309
1310 for (unsigned int i = 0; i < num_threads; ++i)
1311 {
1312 running_threads.emplace_back([i, &results]()
1313 {
1314 /* Use ekm on odd threads */
1315 const bool use_ekm = openvpn::SSLLib::SSLAPI::support_key_material_export() && (i % 2 == 0);
1316 results[i] = test_retry(static_cast<int>(i), N_RETRIES, use_ekm); });
1317 }
1318 for (unsigned int i = 0; i < num_threads; ++i)
1319 {
1320 running_threads[i].join();
1321 }
1322
1323
1324 // expect 1 for all threads
1325 const std::vector<int> expected_results(num_threads, 0);
1326
1327 EXPECT_THAT(expected_results, ::testing::ContainerEq(results));
1328}
1329
1330TEST(proto, iv_ciphers_aead)
1331{
1332 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, true, false);
1333
1334 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1335
1336 auto infostring = protoConf.peer_info_string(false);
1337
1338 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1339 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1340
1341
1342 std::string expectedstr{"IV_CIPHERS=AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1343 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1344 expectedstr += ":CHACHA20-POLY1305";
1345
1346 EXPECT_EQ(ivciphers, expectedstr);
1347}
1348
1349TEST(proto, iv_ciphers_non_preferred)
1350{
1351 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, false, false);
1352
1353 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1354
1355 auto infostring = protoConf.peer_info_string(true);
1356
1357 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1358 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1359
1360
1361 std::string expectedstr{"IV_CIPHERS=AES-128-CBC:AES-192-CBC:AES-256-CBC:AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1362 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1363 expectedstr += ":CHACHA20-POLY1305";
1364
1365 EXPECT_EQ(ivciphers, expectedstr);
1366}
1367
1368TEST(proto, iv_ciphers_legacy)
1369{
1370
1371 /* Need to a whole lot of things to enable legacy provider/OpenSSL context */
1372 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1373 EXPECT_TRUE(config);
1374
1375 StrongRandomAPI::Ptr rng(new SSLLib::RandomAPI());
1376 config->set_rng(rng);
1377
1378 config->set_mode(Mode(Mode::CLIENT));
1380 config->set_local_cert_enabled(false);
1381 config->enable_legacy_algorithms(true);
1382
1383 auto factory_client = config->new_factory();
1384 EXPECT_TRUE(factory_client);
1385
1386 auto client = factory_client->ssl();
1387 auto libctx = factory_client->libctx();
1388
1389
1390 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(libctx, false, true);
1391
1392 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1393
1394 auto infostring = protoConf.peer_info_string(false);
1395
1396 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1397 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1398
1399
1400
1401 std::string expectedstr{"IV_CIPHERS=none:AES-128-CBC:AES-192-CBC:AES-256-CBC:DES-CBC:DES-EDE3-CBC"};
1402
1403 if (SSLLib::CryptoAPI::CipherContext::is_supported(libctx, openvpn::CryptoAlgs::BF_CBC))
1404 expectedstr += ":BF-CBC";
1405
1406 expectedstr += ":AES-128-GCM:AES-192-GCM:AES-256-GCM";
1407
1408 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1409 expectedstr += ":CHACHA20-POLY1305";
1410
1411 EXPECT_EQ(ivciphers, expectedstr);
1412}
1413
1414TEST(proto, controlmessage_invalidchar)
1415{
1416 std::string valid_auth_fail{"AUTH_FAILED: go away"};
1417 std::string valid_auth_fail_newline_end{"AUTH_FAILED: go away\n"};
1418 std::string invalid_auth_fail{"AUTH_FAILED: go\n away\n"};
1419 std::string lot_of_whitespace{"AUTH_FAILED: a lot of white space\n\n\r\n\r\n\r\n"};
1420 std::string only_whitespace{"\n\n\r\n\r\n\r\n"};
1421 std::string empty{""};
1422
1423 BufferAllocated valid_auth_fail_buf{reinterpret_cast<const unsigned char *>(valid_auth_fail.c_str()), valid_auth_fail.size(), BufAllocFlags::GROW};
1424 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};
1425 BufferAllocated invalid_auth_fail_buf{reinterpret_cast<const unsigned char *>(invalid_auth_fail.c_str()), invalid_auth_fail.size(), BufAllocFlags::GROW};
1426 BufferAllocated lot_of_whitespace_buf{reinterpret_cast<const unsigned char *>(lot_of_whitespace.c_str()), lot_of_whitespace.size(), BufAllocFlags::GROW};
1427 BufferAllocated only_whitespace_buf{reinterpret_cast<const unsigned char *>(only_whitespace.c_str()), only_whitespace.size(), BufAllocFlags::GROW};
1428 BufferAllocated empty_buf{reinterpret_cast<const unsigned char *>(empty.c_str()), empty.size(), BufAllocFlags::GROW};
1429
1430 auto msg = ProtoContext::read_control_string<std::string>(valid_auth_fail_buf);
1431 EXPECT_EQ(msg, valid_auth_fail);
1433
1434 auto msg2 = ProtoContext::read_control_string<std::string>(valid_auth_fail_newline_end_buf);
1435 EXPECT_EQ(msg2, valid_auth_fail);
1437
1438 auto msg3 = ProtoContext::read_control_string<std::string>(invalid_auth_fail_buf);
1439 EXPECT_EQ(msg3, "AUTH_FAILED: go\n away");
1440 EXPECT_FALSE(Unicode::is_valid_utf8(msg3, Unicode::UTF8_NO_CTRL));
1441
1442 auto msg4 = ProtoContext::read_control_string<std::string>(lot_of_whitespace_buf);
1443 EXPECT_EQ(msg4, "AUTH_FAILED: a lot of white space");
1445
1446 auto msg5 = ProtoContext::read_control_string<std::string>(only_whitespace_buf);
1447 EXPECT_EQ(msg5, "");
1449
1450 auto msg6 = ProtoContext::read_control_string<std::string>(empty_buf);
1451 EXPECT_EQ(msg6, "");
1453}
1454
1461
1463{
1464 public:
1466 {
1467 events.push_back(event);
1468 }
1469
1470 std::vector<openvpn::ClientEvent::Base::Ptr> events;
1471};
1472
1473TEST(proto, client_proto_check_cc_msg)
1474{
1475 asio::io_context io_context;
1476 ClientRandomAPI::Ptr rng_cli(new ClientRandomAPI());
1477 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1478 MySessionStats::Ptr cli_stats(new MySessionStats);
1479 Time time;
1480
1482 /* keep a reference to the right class to avoid repeated casted */
1483 EventQueueVector *eqv = dynamic_cast<EventQueueVector *>(eqv_ptr.get());
1484 /* check that the cast worked */
1485 ASSERT_TRUE(eqv);
1486
1487 MockCallback mockCB;
1490 frame,
1491 rng_cli,
1492 std::move(cli_stats),
1493 time);
1494 clisessconf.cli_events = std::move(eqv_ptr);
1495 openvpn::ClientProto::Session::Ptr clisession = new ClientProto::Session{io_context, clisessconf, &mockCB};
1496
1497 clisession->validate_and_post_cc_msg("valid message");
1498
1499
1500 EXPECT_TRUE(eqv->events.empty());
1501
1502 clisession->validate_and_post_cc_msg("invalid\nmessage");
1503 EXPECT_EQ(eqv->events.size(), 1);
1504 auto ev = eqv->events.back();
1505 auto uf = dynamic_cast<openvpn::ClientEvent::UnsupportedFeature *>(ev.get());
1506 /* check that the cast worked */
1507 ASSERT_TRUE(uf);
1508 EXPECT_EQ(uf->name, "Invalid chars in control message");
1509 EXPECT_EQ(uf->reason, "Control channel message with invalid characters not allowed to be send with post_cc_msg");
1510}
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:90
void error(const size_t err_type, const std::string *text=nullptr) override
count_t get_error_count(const Error::Type type) const
RCPtr< MySessionStats > Ptr
void show_error_counts() const
BufferPtr recv()
void xfer(T1 &a, T2 &b)
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)
std::deque< BufferPtr > wire
unsigned int rand(const unsigned int prob)
unsigned int reorder_prob
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:1242
T * data()
Get a mutable pointer to the start of the array.
Definition buffer.hpp:1450
size_t prepare(const unsigned int context, Buffer &buf) const
Definition frame.hpp:266
const Time::Duration & slowest_handshake()
Definition proto.hpp:4329
const Time & now() const
Definition proto.hpp:4430
void flush(const bool control_channel)
Definition proto.hpp:4149
void control_send(BufferPtr &&app_bp)
Definition proto.hpp:4206
void data_encrypt(BufferAllocated &in_out)
Definition proto.hpp:4244
static void write_auth_string(const S &str, Buffer &buf)
Definition proto.hpp:1535
bool is_server() const
Definition proto.hpp:4454
bool data_decrypt(const PacketType &type, BufferAllocated &in_out)
Definition proto.hpp:4254
Error::Type invalidation_reason() const
Definition proto.hpp:4341
unsigned int negotiations() const
Definition proto.hpp:4323
Time next_housekeeping() const
Definition proto.hpp:4187
bool invalidated() const
Definition proto.hpp:4335
void reset(const ProtoSessionID cookie_psid=ProtoSessionID())
Resets ProtoContext *this to it's initial state.
Definition proto.hpp:3993
void start(const ProtoSessionID cookie_psid=ProtoSessionID())
Initialize the state machine and start protocol negotiation.
Definition proto.hpp:4123
const ProtoConfig & conf() const
Definition proto.hpp:4474
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:409
static TimeType infinite()
Definition time.hpp:256
bool defined() const
Definition time.hpp:283
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
RCPtr< BufferAllocatedRc > BufferPtr
Definition buffer.hpp:1899
long long count_t
Definition count.hpp:16
ProtoContext::ProtoConfig::Ptr proto_context_config
Definition cliproto.hpp:126
unsigned int mssfix
Definition mssparms.hpp:72
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, base_single_thread_tls_ekm)
#define TLS_VER_MIN
#define N_RETRIES
#define COMP_METH
#define ITER
const char message[]
#define PROTO_CIPHER
#define SITER
#define RENEG
TEST(proto, iv_ciphers_aead)
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,...)