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
363 void reset()
364 {
365 net_out.clear();
366 wkc_pkt_sizes_.clear();
370 }
371
372 void initial_app_send(const char *msg)
373 {
375 const size_t msglen = std::strlen(msg) + 1;
376 BufferAllocated app_buf((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
377 copy_progress(app_buf);
378 control_send(std::move(app_buf));
379 proto_context.flush(true);
380 }
381
382 void app_send_templ_init(const char *msg)
383 {
385 const size_t msglen = std::strlen(msg) + 1;
386 templ = BufferAllocatedRc::Create((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
387 proto_context.flush(true);
388 }
389
391 {
392#if !FEEDBACK
393 if (bool(iteration++ & 1) == is_server())
394 {
395 modmsg(templ);
396 BufferAllocated app_buf(*templ);
397 control_send(std::move(app_buf));
398 flush(true);
400 }
401#endif
402 }
403
405 {
407 {
409 return true;
410 }
411 return false;
412 }
413
414 void control_send(BufferPtr &&app_bp)
415 {
416 app_bytes_ += app_bp->size();
417 proto_context.control_send(std::move(app_bp));
418 }
419
421 {
422 app_bytes_ += app_buf.size();
423 proto_context.control_send(std::move(app_buf));
424 }
425
427 {
430 bp->write((unsigned char *)str, std::strlen(str));
431 data_encrypt(*bp);
432 return bp;
433 }
434
436 {
438 }
439
441 {
442 proto_context.data_decrypt(type, in_out);
443 if (!in_out.empty())
444 {
445 data_bytes_ += in_out.size();
447 }
448 }
449
450 size_t net_bytes() const
451 {
452 return net_bytes_;
453 }
454 size_t app_bytes() const
455 {
456 return app_bytes_;
457 }
458 size_t data_bytes() const
459 {
460 return data_bytes_;
461 }
462 size_t n_control_recv() const
463 {
464 return n_control_recv_;
465 }
466 size_t n_control_send() const
467 {
468 return n_control_send_;
469 }
470
471 const char *progress() const
472 {
473 return progress_;
474 }
475
476 void finalize()
477 {
480 }
481
483 {
485 throw session_invalidated(Error::name(proto_context.invalidation_reason()));
486 }
487
489 {
490 disable_xmit_ = true;
491 }
492
494
495 std::deque<BufferPtr> net_out;
496
497 // sizes of the CONTROL_WKC_V1 packets (the tls-crypt-v2 WKc riders)
498 // emitted via control_net_send(). Only these are recorded, so the
499 // vector stays tiny even across the long feedback tests.
500 std::vector<size_t> wkc_pkt_sizes_;
501
502 // largest control channel packet emitted via control_net_send()
504
505 size_t max_ctrl_pkt_size() const
506 {
507 return max_ctrl_pkt_size_;
508 }
509
510 // Verify every emitted CONTROL_WKC_V1 packet fits within max_size,
511 // and that at least one such packet was emitted.
512 bool verify_wkc_packets_fit(size_t max_size) const
513 {
514 if (wkc_pkt_sizes_.empty())
515 {
516 std::cerr << "no CONTROL_WKC_V1 packet was emitted by the client\n";
517 return false;
518 }
519 for (const size_t size : wkc_pkt_sizes_)
520 {
521 if (size > max_size)
522 {
523 std::cerr << "CONTROL_WKC_V1 packet too large: " << size
524 << " > " << max_size << '\n';
525 return false;
526 }
527 }
528 return true;
529 }
530
533
534 private:
535 void control_net_send(const Buffer &net_buf) override
536 {
537 if (disable_xmit_)
538 return;
539 net_bytes_ += net_buf.size();
540 max_ctrl_pkt_size_ = std::max(max_ctrl_pkt_size_, net_buf.size());
541 if (net_buf.size()
543 wkc_pkt_sizes_.push_back(net_buf.size());
545 }
546
547 void control_recv(BufferPtr &&app_bp) override
548 {
550 work.swap(app_bp);
551 if (work->size() >= 23)
552 std::memcpy(progress_, work->data() + 13, 10);
553
554#ifdef VERBOSE
555 {
556 const ssize_t trunc = 64;
557 const std::string show((char *)work->data(), trunc);
558 std::cout << now().raw() << " " << mode().str() << " " << show << "\n";
559 }
560#endif
561#if FEEDBACK
562 modmsg(work);
563 control_send(std::move(work));
564#endif
567 }
568
570 {
571 if (progress_[0]) // make sure progress was initialized
572 std::memcpy(buf.data() + 13, progress_, 10);
573 }
574
575 void modmsg(BufferPtr &buf)
576 {
577 char *msg = (char *)buf->data();
579 {
580 msg[8] = 'S';
581 msg[11] = 'C';
582 }
583 else
584 {
585 msg[8] = 'C';
586 msg[11] = 'S';
587 }
588
589 // increment embedded number
590 for (int i = 22; i >= 13; i--)
591 {
592 if (msg[i] != '9')
593 {
594 msg[i]++;
595 break;
596 }
597 msg[i] = '0';
598 }
599 }
600
602 size_t app_bytes_ = 0;
603 size_t net_bytes_ = 0;
604 size_t data_bytes_ = 0;
605 size_t n_control_send_ = 0;
606 size_t n_control_recv_ = 0;
608#if !FEEDBACK
609 size_t iteration = 0;
610#endif
611 char progress_[11];
612 bool disable_xmit_ = false;
613};
614
616{
618
619 public:
621 const SessionStats::Ptr &stats)
622 : TestProto(config, stats)
623 {
624 }
625
626 private:
627 void client_auth(Buffer &buf) override
628 {
629 const std::string username("foo");
630 const std::string password("bar");
631 ProtoContext::write_auth_string(username, buf);
632 ProtoContext::write_auth_string(password, buf);
633 }
634};
635
637{
638
639 public:
640 void start()
641 {
643 }
644
646
647
649 const SessionStats::Ptr &stats)
650 : TestProto(config, stats)
651 {
652 }
653
654 private:
655 void server_auth(const std::string &username,
656 const SafeString &password,
657 const std::string &peer_info,
658 const AuthCert::Ptr &auth_cert) override
659 {
660#ifdef VERBOSE
661 std::cout << "**** AUTHENTICATE " << username << '/' << password << " PEER INFO:\n";
662 std::cout << peer_info;
663#endif
664 if (username != "foo" || password != "bar")
665 throw auth_failed();
666 }
667};
668
669// Simulate a noisy transmission channel where packets can be dropped,
670// reordered, or corrupted.
672{
673 public:
674 NoisyWire(const std::string &title_arg,
675 TimePtr now_arg,
676 RandomAPI &rand_arg,
677 const unsigned int reorder_prob_arg,
678 const unsigned int drop_prob_arg,
679 const unsigned int corrupt_prob_arg)
680 : title(title_arg),
681#ifdef VERBOSE
682 now(now_arg),
683#endif
684 random(rand_arg),
685 reorder_prob(reorder_prob_arg),
686 drop_prob(drop_prob_arg),
687 corrupt_prob(corrupt_prob_arg)
688 {
689 }
690
691 template <typename T1, typename T2>
692 void xfer(T1 &a, T2 &b)
693 {
694 // check for errors
695 a.check_invalidated();
696 b.check_invalidated();
697
698 // need to retransmit?
699 if (a.do_housekeeping())
700 {
701#ifdef VERBOSE
702 std::cout << now->raw() << " " << title << " Housekeeping\n";
703#endif
704 }
705
706 // queue a control channel packet
707 a.app_send_templ();
708
709 // queue a data channel packet
710 if (a.proto_context.data_channel_ready())
711 {
712 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...");
713 wire.push_back(bp);
714 }
715
716 // transfer network packets from A -> wire
717 while (!a.net_out.empty())
718 {
719 BufferPtr bp = a.net_out.front();
720#ifdef VERBOSE
721 std::cout << now->raw() << " " << title << " " << a.dump_packet(*bp) << "\n";
722#endif
723 a.net_out.pop_front();
724 wire.push_back(bp);
725 }
726
727 // transfer network packets from wire -> B
728 while (true)
729 {
730 BufferPtr bp = recv();
731 if (!bp)
732 break;
733 typename ProtoContext::PacketType pt = b.proto_context.packet_type(*bp);
734 if (pt.is_control())
735 {
736#ifdef VERBOSE
737 if (!b.control_net_validate(pt, *bp)) // not strictly necessary since control_net_recv will also validate
738 std::cout << now->raw() << " " << title << " CONTROL PACKET VALIDATION FAILED\n";
739#endif
740 b.proto_context.control_net_recv(pt, std::move(bp));
741 }
742 else if (pt.is_data())
743 {
744 try
745 {
746 b.data_decrypt(pt, *bp);
747#ifdef VERBOSE
748 if (bp->size())
749 {
750 const std::string show((char *)bp->data(), std::min(bp->size(), size_t(40)));
751 std::cout << now->raw() << " " << title << " DATA CHANNEL DECRYPT: " << show << "\n";
752 }
753#endif
754 }
755 catch ([[maybe_unused]] const std::exception &e)
756 {
757#ifdef VERBOSE
758 std::cout << now->raw() << " " << title << " Exception on data channel decrypt: " << e.what() << "\n";
759#endif
760 }
761 }
762 else
763 {
764#ifdef VERBOSE
765 std::cout << now->raw() << " " << title << " KEY_STATE_ERROR\n";
766#endif
767 b.proto_context.stat().error(Error::KEY_STATE_ERROR);
768 }
769
770#ifdef SIMULATE_UDP_AMPLIFY_ATTACK
771 if (b.proto_context.is_state_client_wait_reset_ack())
772 {
773 b.disable_xmit();
774#ifdef VERBOSE
775 std::cout << now->raw() << " " << title << " SIMULATE_UDP_AMPLIFY_ATTACK disable client xmit\n";
776#endif
777 }
778#endif
779 }
780 b.proto_context.flush(true);
781 }
782
783 private:
785 {
786#ifdef SIMULATE_OOO
787 // simulate packets being received out of order
788 if (wire.size() >= 2 && !rand(reorder_prob))
789 {
790 const size_t i = random.randrange(wire.size() - 1) + 1;
791#ifdef VERBOSE
792 std::cout << now->raw() << " " << title << " Simulating packet reordering " << i << " -> 0\n";
793#endif
794 std::swap(wire[0], wire[i]);
795 }
796#endif
797
798 if (!wire.empty())
799 {
800 BufferPtr bp = wire.front();
801 wire.pop_front();
802
803#ifdef VERBOSE
804 std::cout << now->raw() << " " << title << " Received packet, size=" << bp->size() << "\n";
805#endif
806
807#ifdef SIMULATE_DROPPED
808 // simulate dropped packet
809 if (!rand(drop_prob))
810 {
811#ifdef VERBOSE
812 std::cout << now->raw() << " " << title << " Simulating a dropped packet\n";
813#endif
814 return BufferPtr();
815 }
816#endif
817
818#ifdef SIMULATE_CORRUPTED
819 // simulate corrupted packet
820 if (!bp->empty() && !rand(corrupt_prob))
821 {
822#ifdef VERBOSE
823 std::cout << now->raw() << " " << title << " Simulating a corrupted packet\n";
824#endif
825 const size_t pos = random.randrange(bp->size());
826 const unsigned char value = random.randrange(std::numeric_limits<unsigned char>::max());
827 (*bp)[pos] = value;
828 }
829#endif
830 return bp;
831 }
832
833 return BufferPtr();
834 }
835
836 unsigned int rand(const unsigned int prob)
837 {
838 if (prob)
839 return random.randrange(prob);
840 return 1;
841 }
842
843 std::string title;
844#ifdef VERBOSE
845 TimePtr now;
846#endif
848 unsigned int reorder_prob;
849 unsigned int drop_prob;
850 unsigned int corrupt_prob;
851 std::deque<BufferPtr> wire;
852};
853
854class MySessionStats : public SessionStats
855{
856 public:
858
860 {
861 std::memset(errors, 0, sizeof(errors));
862 }
863
864 void error(const size_t err_type, const std::string *text = nullptr) override
865 {
866 if (err_type < Error::N_ERRORS)
867 ++errors[err_type];
868 }
869
871 {
872 if (type < Error::N_ERRORS)
873 return errors[type];
874 return 0;
875 }
876
877 void show_error_counts() const
878 {
879 for (size_t i = 0; i < Error::N_ERRORS; ++i)
880 {
881 count_t c = errors[i];
882 if (c)
883 std::cerr << Error::name(i) << " : " << c << '\n';
884 }
885 }
886
887 private:
889};
890
895static auto create_client_ssl_config(Frame::Ptr frame, ClientRandomAPI::Ptr rng, bool tls_version_mismatch = false)
896{
897 const std::string client_crt = read_text(TEST_KEYCERT_DIR "client.crt");
898 const std::string client_key = read_text(TEST_KEYCERT_DIR "client.key");
899 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
900
901 // client config
902 ClientSSLAPI::Config::Ptr cc(new ClientSSLAPI::Config());
903 cc->set_mode(Mode(Mode::CLIENT));
904 cc->set_frame(frame);
905 cc->set_rng(rng);
906#ifdef USE_APPLE_SSL
907 cc->load_identity("etest");
908#else
909 cc->load_ca(ca_crt, true);
910 cc->load_cert(client_crt);
911 cc->load_private_key(client_key);
912#endif
913 if (tls_version_mismatch)
914 cc->set_tls_version_max(TLSVersion::Type::V1_2);
915 else
916 cc->set_tls_version_min(TLS_VER_MIN);
917#ifdef VERBOSE
918 cc->set_debug_level(1);
919#endif
920 return cc;
921}
922
923static 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 = "")
924
925{
926 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
927 const std::string tls_crypt_v2_client_key = tls_crypt_v2_key_fn.empty()
928 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-client.key")
929 : read_text(TEST_KEYCERT_DIR + tls_crypt_v2_key_fn);
930
931 // client ProtoContext config
932 using ClientProtoContext = ProtoContext;
933 ClientProtoContext::ProtoConfig::Ptr cp(new ClientProtoContext::ProtoConfig);
934 cp->ssl_factory = cc->new_factory();
935 CryptoAlgs::allow_default_dc_algs<ClientCryptoAPI>(cp->ssl_factory->libctx(), false, false);
936 cp->dc.set_factory(new CryptoDCSelect<ClientCryptoAPI>(cp->ssl_factory->libctx(), frame, cli_stats, rng));
937 cp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ClientCryptoAPI>());
938 cp->frame = std::move(frame);
939 cp->now = &time;
940 cp->rng = rng;
941 cp->prng = rng;
942 cp->protocol = Protocol(Protocol::UDPv4);
943 cp->layer = Layer(Layer::OSI_LAYER_3);
944#ifdef PROTOv2
945 cp->enable_op32 = true;
946 cp->remote_peer_id = 100;
947#endif
948 cp->comp_ctx = CompressContext(COMP_METH, false);
949 cp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
950 cp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
951
952#ifdef USE_TLS_AUTH
953 cp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ClientCryptoAPI>());
954 cp->tls_auth_key.parse(tls_auth_key);
955 cp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
956 cp->key_direction = 0;
957#endif
958#ifdef USE_TLS_CRYPT
959 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
960 cp->tls_crypt_key.parse(tls_auth_key);
961 cp->set_tls_crypt_algs();
962 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
963#endif
964#ifdef USE_TLS_CRYPT_V2
965 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
966 cp->set_tls_crypt_algs();
967 {
968 TLSCryptV2ClientKey tls_crypt_v2_key(cp->tls_crypt_context);
969 tls_crypt_v2_key.parse(tls_crypt_v2_client_key);
970 tls_crypt_v2_key.extract_key(cp->tls_crypt_key);
971 tls_crypt_v2_key.extract_wkc(cp->wkc);
972 }
973 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
974#endif
975#ifdef HANDSHAKE_WINDOW
976 cp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
977#elif SITER > 1
978 cp->handshake_window = Time::Duration::seconds(30);
979#else
980 cp->handshake_window = Time::Duration::seconds(18); // will cause a small number of handshake failures
981#endif
982#ifdef BECOME_PRIMARY_CLIENT
983 cp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_CLIENT);
984#else
985 cp->become_primary = cp->handshake_window;
986#endif
987 cp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_CLIENT);
988#ifdef CLIENT_NO_RENEG
989 cp->renegotiate = Time::Duration::infinite();
990#else
991 cp->renegotiate = Time::Duration::seconds(RENEG);
992#endif
993 cp->expire = cp->renegotiate + cp->renegotiate;
994 cp->keepalive_ping = Time::Duration::seconds(5);
995 cp->keepalive_timeout = Time::Duration::seconds(60);
996 cp->keepalive_timeout_early = cp->keepalive_timeout;
997
998#ifdef VERBOSE
999 std::cout << "CLIENT OPTIONS: " << cp->options_string() << "\n";
1000 std::cout << "CLIENT PEER INFO:\n";
1001 std::cout << cp->peer_info_string();
1002#endif
1003 return cp;
1004}
1005
1006// Configures one specific test run */
1008{
1009 bool use_tls_ekm = false;
1011 const std::string &tls_crypt_v2_key_fn = "";
1013 bool force_resend_wkc = false;
1014 size_t control_payload = 378;
1015 size_t mssfix_ctrl = 0;
1016};
1017
1018// execute the unit test in one thread
1019int test(const struct proto_test &t)
1020{
1021 try
1022 {
1023 // frame
1024 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1025 // Shrink only the control-channel ciphertext context, mirroring what
1026 // mssfix-ctrl does in production (see frame_init()): the cleartext
1027 // staging buffers (e.g. WRITE_SSL_CLEARTEXT, used for the auth
1028 // message) keep their normal size.
1030
1031 // RNG
1032 ClientRandomAPI::Ptr prng_cli(new ClientRandomAPI());
1033 ServerRandomAPI::Ptr prng_serv(new ServerRandomAPI());
1034 MTRand rng_noncrypto;
1035
1036 // init simulated time
1037 Time time;
1038 const Time::Duration time_step = Time::Duration::binary_ms(100);
1039
1040 // config files
1041 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
1042 const std::string server_crt = read_text(TEST_KEYCERT_DIR "server.crt");
1043 const std::string server_key = read_text(TEST_KEYCERT_DIR "server.key");
1044 const std::string dh_pem = read_text(TEST_KEYCERT_DIR "dh.pem");
1045 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
1046 const std::string tls_crypt_v2_server_key = t.tls_crypt_v2_key_fn.empty()
1047 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-server.key")
1048 : "";
1049
1050 // client config
1051 ClientSSLAPI::Config::Ptr cc = create_client_ssl_config(frame, prng_cli, t.tls_version_mismatch);
1052 MySessionStats::Ptr cli_stats(new MySessionStats);
1053
1054 auto cp = create_client_proto_context(std::move(cc), frame, prng_cli, cli_stats, time, t.tls_crypt_v2_key_fn);
1055 if (t.use_tls_ekm)
1056 cp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1057 if (t.mssfix_ctrl)
1058 cp->mssfix_ctrl = t.mssfix_ctrl;
1059
1060 // server config
1061 MySessionStats::Ptr serv_stats(new MySessionStats);
1062
1063 ServerSSLAPI::Config::Ptr sc(new ClientSSLAPI::Config());
1064 sc->set_mode(Mode(Mode::SERVER));
1065 sc->set_frame(frame);
1066 sc->set_rng(prng_serv);
1067 sc->load_ca(ca_crt, true);
1068 sc->load_cert(server_crt);
1069 sc->load_private_key(server_key);
1070 sc->load_dh(dh_pem);
1071 sc->set_tls_version_min(t.tls_version_mismatch ? TLSVersion::Type::V1_3 : TLS_VER_MIN);
1072#ifdef VERBOSE
1073 sc->set_debug_level(1);
1074#endif
1075
1076 // server ProtoContext config
1077 using ServerProtoContext = ProtoContext;
1078 ServerProtoContext::ProtoConfig::Ptr sp(new ServerProtoContext::ProtoConfig);
1079 sp->ssl_factory = sc->new_factory();
1080 sp->dc.set_factory(new CryptoDCSelect<ServerCryptoAPI>(sp->ssl_factory->libctx(), frame, serv_stats, prng_serv));
1081 sp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ServerCryptoAPI>());
1082 sp->frame = frame;
1083 sp->now = &time;
1084 sp->rng = prng_serv;
1085 sp->prng = prng_serv;
1086 sp->protocol = Protocol(Protocol::UDPv4);
1087 sp->layer = Layer(Layer::OSI_LAYER_3);
1088#ifdef PROTOv2
1089 sp->enable_op32 = true;
1090 sp->remote_peer_id = 101;
1091#endif
1092 sp->comp_ctx = CompressContext(COMP_METH, false);
1093 sp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
1094 sp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1095 if (t.use_tls_ekm)
1096 sp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1097#ifdef USE_TLS_AUTH
1098 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1099 sp->tls_auth_key.parse(tls_auth_key);
1100 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1101 sp->key_direction = 1;
1102#endif
1103#ifdef USE_TLS_CRYPT
1104 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1105 sp->tls_crypt_key.parse(tls_auth_key);
1106 sp->set_tls_crypt_algs();
1107 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
1108#endif
1109#ifdef USE_TLS_CRYPT_V2
1110 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1111
1112 if (t.tls_crypt_v2_key_fn.empty())
1113 {
1114 TLSCryptV2ServerKey tls_crypt_v2_key;
1115 tls_crypt_v2_key.parse(tls_crypt_v2_server_key);
1116 tls_crypt_v2_key.extract_key(sp->tls_crypt_key);
1117 }
1118
1119 sp->set_tls_crypt_algs();
1120 sp->tls_crypt_metadata_factory.reset(new CryptoTLSCryptMetadataFactory());
1121 sp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
1122 sp->tls_crypt_v2_serverkey_id = !t.tls_crypt_v2_key_fn.empty();
1123 sp->tls_crypt_v2_serverkey_dir = TEST_KEYCERT_DIR;
1124
1126 {
1127 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1128 sp->tls_auth_key.parse(tls_auth_key);
1129 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1130 sp->key_direction = 1;
1131 }
1132#endif
1133#ifdef HANDSHAKE_WINDOW
1134 sp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
1135#elif SITER > 1
1136 sp->handshake_window = Time::Duration::seconds(30);
1137#else
1138 sp->handshake_window = Time::Duration::seconds(17) + Time::Duration::binary_ms(512);
1139#endif
1140#ifdef BECOME_PRIMARY_SERVER
1141 sp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_SERVER);
1142#else
1143 sp->become_primary = sp->handshake_window;
1144#endif
1145 sp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_SERVER);
1146#ifdef SERVER_NO_RENEG
1147 sp->renegotiate = Time::Duration::infinite();
1148#else
1149 // NOTE: if we don't add sp->handshake_window, both client and server reneg-sec (RENEG)
1150 // will be equal and will therefore occasionally collide. Such collisions can sometimes
1151 // produce this OpenSSL error:
1152 // OpenSSLContext::SSL::read_cleartext: BIO_read failed, cap=400 status=-1: error:140E0197:SSL routines:SSL_shutdown:shutdown while in init
1153 // The issue was introduced by this patch in OpenSSL:
1154 // https://github.com/openssl/openssl/commit/64193c8218540499984cd63cda41f3cd491f3f59
1155 sp->renegotiate = Time::Duration::seconds(RENEG) + sp->handshake_window;
1156#endif
1157 sp->expire = sp->renegotiate + sp->renegotiate;
1158 sp->keepalive_ping = Time::Duration::seconds(5);
1159 sp->keepalive_timeout = Time::Duration::seconds(60);
1160 sp->keepalive_timeout_early = Time::Duration::seconds(10);
1161
1162#ifdef VERBOSE
1163 std::cout << "SERVER OPTIONS: " << sp->options_string() << "\n";
1164 std::cout << "SERVER PEER INFO:\n";
1165 std::cout << sp->peer_info_string();
1166#endif
1167
1168 TestProtoClient cli_proto(cp, cli_stats);
1169 TestProtoServer serv_proto(sp, serv_stats);
1170
1171 for (int i = 0; i < SITER; ++i)
1172 {
1173#ifdef VERBOSE
1174 std::cout << "***** SITER " << i << "\n";
1175#endif
1176 cli_proto.reset();
1177 serv_proto.reset();
1178
1179 NoisyWire client_to_server("Client -> Server", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1180 NoisyWire server_to_client("Server -> Client", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1181
1182 int j = -1;
1183 try
1184 {
1185#if FEEDBACK
1186 // start feedback loop
1187 cli_proto.initial_app_send(message);
1188 serv_proto.start();
1189#else
1190 cli_proto.app_send_templ_init(message);
1191 serv_proto.app_send_templ_init(message);
1192#endif
1193
1194 if (t.force_resend_wkc)
1195 {
1196 // Pretend the server asked the client to resend the
1197 // tls-crypt-v2 WKc on the first control packet, so the
1198 // client's ClientHello is emitted as CONTROL_WKC_V1 with
1199 // the WKc appended. Drive only enough rounds for the
1200 // client to emit it, then verify it fits the control-channel
1201 // frame. The handshake won't complete (a plain ProtoContext
1202 // server doesn't expect a WKc on a mid-handshake
1203 // CONTROL_WKC_V1), which is irrelevant to this check.
1204 cli_proto.proto_context.force_resend_wkc();
1205 for (int k = 0; k < 60; ++k)
1206 {
1207 client_to_server.xfer(cli_proto, serv_proto);
1208 server_to_client.xfer(serv_proto, cli_proto);
1209 time += time_step;
1210 }
1211 // Frame control context above is Context(128, control_payload, ...).
1212 // Even the WKc-bearing packet must stay within headroom +
1213 // payload; without the reservation fix it overflows by
1214 // ~wkc.size() bytes.
1215 if (!cli_proto.verify_wkc_packets_fit(128 + t.control_payload))
1216 return 1;
1217 // when a wire cap is configured, every emitted control
1218 // packet must stay within it after all wrappings
1219 if (t.mssfix_ctrl && cli_proto.max_ctrl_pkt_size() > t.mssfix_ctrl)
1220 {
1221 std::cerr << "control packet exceeded mssfix_ctrl: "
1222 << cli_proto.max_ctrl_pkt_size()
1223 << " > " << t.mssfix_ctrl << '\n';
1224 return 1;
1225 }
1226 return 0;
1227 }
1228
1229 // message loop
1230 for (j = 0; j < ITER; ++j)
1231 {
1232 client_to_server.xfer(cli_proto, serv_proto);
1233 server_to_client.xfer(serv_proto, cli_proto);
1234 time += time_step;
1235 }
1236 }
1237 catch (const std::exception &e)
1238 {
1239 std::cerr << "Exception[" << i << '/' << j << "]: " << e.what() << '\n';
1240 return 1;
1241 }
1242 }
1243
1244 cli_proto.finalize();
1245 serv_proto.finalize();
1246
1247 const size_t ab = cli_proto.app_bytes() + serv_proto.app_bytes();
1248 const size_t nb = cli_proto.net_bytes() + serv_proto.net_bytes();
1249 const size_t db = cli_proto.data_bytes() + serv_proto.data_bytes();
1250
1251 std::cerr << "*** app bytes=" << ab
1252 << " net_bytes=" << nb
1253 << " data_bytes=" << db
1254 << " prog=" << cli_proto.progress() << '/' << serv_proto.progress()
1255#if !FEEDBACK
1256 << " CTRL=" << cli_proto.n_control_recv() << '/' << cli_proto.n_control_send() << '/' << serv_proto.n_control_recv() << '/' << serv_proto.n_control_send()
1257#endif
1258 << " D=" << cli_proto.control_drought().raw() << '/' << cli_proto.data_drought().raw() << '/' << serv_proto.control_drought().raw() << '/' << serv_proto.data_drought().raw()
1259 << " N=" << cli_proto.proto_context.negotiations() << '/' << serv_proto.proto_context.negotiations()
1260 << " SH=" << cli_proto.proto_context.slowest_handshake().raw() << '/' << serv_proto.proto_context.slowest_handshake().raw()
1261 << " HE=" << cli_stats->get_error_count(Error::HANDSHAKE_TIMEOUT) << '/' << serv_stats->get_error_count(Error::HANDSHAKE_TIMEOUT)
1262 << '\n';
1263
1264#ifdef STATS
1265 std::cerr << "-------- CLIENT STATS --------\n";
1266 cli_stats->show_error_counts();
1267 std::cerr << "-------- SERVER STATS --------\n";
1268 serv_stats->show_error_counts();
1269#endif
1270#ifdef OPENVPN_MAX_DATALIMIT_BYTES
1271 std::cerr << "------------------------------\n";
1272 std::cerr << "MAX_DATALIMIT_BYTES=" << DataLimit::max_bytes() << "\n";
1273#endif
1274 }
1275 catch (const std::exception &e)
1276 {
1277 std::cerr << "Exception: " << e.what() << '\n';
1278 return 1;
1279 }
1280 return 0;
1281}
1282
1283int test_retry(const int n_retries, const struct proto_test &test_config)
1284{
1285 int ret = 1;
1286 for (int i = 0; i < n_retries; ++i)
1287 {
1288 ret = test(test_config);
1289 if (!ret)
1290 return 0;
1291 std::cout << "Retry " << (i + 1) << '/' << n_retries << '\n';
1292 }
1293 std::cout << "Failed\n";
1294 return ret;
1295}
1296
1297class ProtoUnitTest : public testing::Test
1298{
1299 // Sets up the test fixture.
1300 void SetUp() override
1301 {
1302#ifdef USE_MBEDTLS
1303 mbedtls_debug_set_threshold(1);
1304#endif
1305
1307
1308#ifdef PROTO_VERBOSE
1310#else
1312#endif
1313 }
1314
1315 // Tears down the test fixture.
1316 void TearDown() override
1317 {
1318#ifdef USE_MBEDTLS
1319 mbedtls_debug_set_threshold(4);
1320#endif
1323 }
1324};
1325
1326TEST_F(ProtoUnitTest, BaseSingleThreadTlsEkm)
1327{
1328 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1329 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1330
1331 int ret = 0;
1332
1333 ret = test_retry(N_RETRIES, {.use_tls_ekm = true});
1334
1335 EXPECT_EQ(ret, 0);
1336}
1337
1338TEST_F(ProtoUnitTest, BaseSingleThreadNoTlsEkm)
1339{
1340 int ret = 0;
1341
1342 ret = test_retry(N_RETRIES, {.use_tls_ekm = false});
1343
1344 EXPECT_EQ(ret, 0);
1345}
1346
1347// Our mbedtls currently has a no-op set_tls_version_max() implementation,
1348// so we can't set mismatched client and server TLS versions.
1349// For now, just test this for OPENSSL which is full-featured.
1350#ifdef USE_OPENSSL
1351TEST_F(ProtoUnitTest, BaseSingleThreadTlsVersionMismatch)
1352{
1353 int ret = test({.tls_version_mismatch = true});
1354 EXPECT_NE(ret, 0);
1355}
1356#endif
1357
1358#ifdef USE_TLS_CRYPT_V2
1359TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithEmbeddedServerkey)
1360{
1361 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key"});
1362 EXPECT_EQ(ret, 0);
1363}
1364
1365TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithMissingEmbeddedServerkey)
1366{
1367 int ret = test({.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-missing-serverkey.key"});
1368 EXPECT_NE(ret, 0);
1369}
1370
1371TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithTlsAuthAlsoActive)
1372{
1373 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key", .use_tls_auth_with_tls_crypt_v2 = true});
1374 EXPECT_EQ(ret, 0);
1375}
1376
1377// Regression test: when the tls-crypt-v2 WKc is appended to the first
1378// ciphertext-bearing control packet (EARLY_NEG_FLAG_RESEND_WKC -> the client
1379// emits CONTROL_WKC_V1), the SSL ciphertext placed into that packet must be
1380// trimmed to leave room for the WKc, so the assembled datagram still fits the
1381// control-channel frame. Without the reservation fix the packet overflows the
1382// frame by ~wkc.size() bytes and gets dropped, stalling the handshake.
1383TEST_F(ProtoUnitTest, TlsCryptV2WkcRidesFirstControlPacket)
1384{
1385 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key", .force_resend_wkc = true});
1386 EXPECT_EQ(ret, 0);
1387}
1388
1389// Degenerate variant of the above: the control-channel payload is smaller
1390// than the WKc itself (mssfix-ctrl may go as low as 256 while a WKc can be
1391// up to 1024 bytes). The WKc reservation must clamp instead of wrapping the
1392// unsigned subtraction -- a wrap disables the trim entirely and the WKc
1393// packet overflows the frame again. The WKc of the test key is 328 bytes;
1394// 278 puts the payload just below it.
1395TEST_F(ProtoUnitTest, TlsCryptV2WkcLargerThanControlPayload)
1396{
1397 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key", .force_resend_wkc = true, .control_payload = 278});
1398 EXPECT_EQ(ret, 0);
1399}
1400
1401// Every control packet, including the WKc-bearing one, must stay within the
1402// configured mssfix_ctrl limit after all tls wrappings have been applied.
1403// 420 leaves just enough room for the unsplittable WKc packet (~406 bytes
1404// worst case: tls-crypt header + full ACK block + the 328 byte WKc).
1405TEST_F(ProtoUnitTest, TlsCryptV2ControlPacketCapHonored)
1406{
1407 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key", .force_resend_wkc = true, .mssfix_ctrl = 420});
1408 EXPECT_EQ(ret, 0);
1409}
1410#endif
1411
1412TEST_F(ProtoUnitTest, BaseMultipleThread)
1413{
1414 unsigned int num_threads = std::thread::hardware_concurrency();
1415#if defined(PROTO_N_THREADS) && PROTO_N_THREADS >= 1
1416 num_threads = PROTO_N_THREADS;
1417#endif
1418
1419 std::vector<std::thread> running_threads{};
1420 std::vector<int> results(num_threads, -777);
1421
1422 for (unsigned int i = 0; i < num_threads; ++i)
1423 {
1424 running_threads.emplace_back([i, &results]()
1425 {
1426 /* Use ekm on odd threads */
1427 const bool use_ekm = openvpn::SSLLib::SSLAPI::support_key_material_export() && (i % 2 == 0);
1428 results[i] = test_retry(N_RETRIES, { .use_tls_ekm = use_ekm }); });
1429 }
1430 for (unsigned int i = 0; i < num_threads; ++i)
1431 {
1432 running_threads[i].join();
1433 }
1434
1435
1436 // expect 1 for all threads
1437 const std::vector<int> expected_results(num_threads, 0);
1438
1439 EXPECT_THAT(expected_results, ::testing::ContainerEq(results));
1440}
1441
1442TEST(Proto, IvCiphersAead)
1443{
1444 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, true, false);
1445
1446 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1447
1448 auto infostring = protoConf.peer_info_string(false);
1449
1450 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1451 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1452
1453
1454 std::string expectedstr{"IV_CIPHERS=AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1455 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1456 expectedstr += ":CHACHA20-POLY1305";
1457
1458 EXPECT_EQ(ivciphers, expectedstr);
1459}
1460
1461TEST(Proto, IvCiphersNonPreferred)
1462{
1463 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, false, false);
1464
1465 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1466
1467 auto infostring = protoConf.peer_info_string(true);
1468
1469 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1470 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1471
1472
1473 std::string expectedstr{"IV_CIPHERS=AES-128-CBC:AES-192-CBC:AES-256-CBC:AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1474 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1475 expectedstr += ":CHACHA20-POLY1305";
1476
1477 EXPECT_EQ(ivciphers, expectedstr);
1478}
1479
1480TEST(Proto, IvCiphersLegacy)
1481{
1482
1483 /* Need to a whole lot of things to enable legacy provider/OpenSSL context */
1484 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1485 EXPECT_TRUE(config);
1486
1487 StrongRandomAPI::Ptr rng(new SSLLib::RandomAPI());
1488 config->set_rng(rng);
1489
1490 config->set_mode(Mode(Mode::CLIENT));
1492 config->set_local_cert_enabled(false);
1493 config->enable_legacy_algorithms(true);
1494
1495 auto factory_client = config->new_factory();
1496 EXPECT_TRUE(factory_client);
1497
1498 auto client = factory_client->ssl();
1499 auto libctx = factory_client->libctx();
1500
1501
1502 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(libctx, false, true);
1503
1504 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1505
1506 auto infostring = protoConf.peer_info_string(false);
1507
1508 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1509 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1510
1511
1512
1513 std::string expectedstr{"IV_CIPHERS=none:AES-128-CBC:AES-192-CBC:AES-256-CBC:DES-CBC:DES-EDE3-CBC"};
1514
1515 if (SSLLib::CryptoAPI::CipherContext::is_supported(libctx, openvpn::CryptoAlgs::BF_CBC))
1516 expectedstr += ":BF-CBC";
1517
1518 expectedstr += ":AES-128-GCM:AES-192-GCM:AES-256-GCM";
1519
1520 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1521 expectedstr += ":CHACHA20-POLY1305";
1522
1523 EXPECT_EQ(ivciphers, expectedstr);
1524}
1525
1526TEST(Proto, ControlmessageInvalidchar)
1527{
1528 std::string valid_auth_fail{"AUTH_FAILED: go away"};
1529 std::string valid_auth_fail_newline_end{"AUTH_FAILED: go away\n"};
1530 std::string invalid_auth_fail{"AUTH_FAILED: go\n away\n"};
1531 std::string lot_of_whitespace{"AUTH_FAILED: a lot of white space\n\n\r\n\r\n\r\n"};
1532 std::string only_whitespace{"\n\n\r\n\r\n\r\n"};
1533 std::string empty{""};
1534
1535 BufferAllocated valid_auth_fail_buf{reinterpret_cast<const unsigned char *>(valid_auth_fail.c_str()), valid_auth_fail.size(), BufAllocFlags::GROW};
1536 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};
1537 BufferAllocated invalid_auth_fail_buf{reinterpret_cast<const unsigned char *>(invalid_auth_fail.c_str()), invalid_auth_fail.size(), BufAllocFlags::GROW};
1538 BufferAllocated lot_of_whitespace_buf{reinterpret_cast<const unsigned char *>(lot_of_whitespace.c_str()), lot_of_whitespace.size(), BufAllocFlags::GROW};
1539 BufferAllocated only_whitespace_buf{reinterpret_cast<const unsigned char *>(only_whitespace.c_str()), only_whitespace.size(), BufAllocFlags::GROW};
1540 BufferAllocated empty_buf{reinterpret_cast<const unsigned char *>(empty.c_str()), empty.size(), BufAllocFlags::GROW};
1541
1542 auto msg = ProtoContext::read_control_string<std::string>(valid_auth_fail_buf);
1543 EXPECT_EQ(msg, valid_auth_fail);
1545
1546 auto msg2 = ProtoContext::read_control_string<std::string>(valid_auth_fail_newline_end_buf);
1547 EXPECT_EQ(msg2, valid_auth_fail);
1549
1550 auto msg3 = ProtoContext::read_control_string<std::string>(invalid_auth_fail_buf);
1551 EXPECT_EQ(msg3, "AUTH_FAILED: go\n away");
1552 EXPECT_FALSE(Unicode::is_valid_utf8(msg3, Unicode::UTF8_NO_CTRL));
1553
1554 auto msg4 = ProtoContext::read_control_string<std::string>(lot_of_whitespace_buf);
1555 EXPECT_EQ(msg4, "AUTH_FAILED: a lot of white space");
1557
1558 auto msg5 = ProtoContext::read_control_string<std::string>(only_whitespace_buf);
1559 EXPECT_EQ(msg5, "");
1561
1562 auto msg6 = ProtoContext::read_control_string<std::string>(empty_buf);
1563 EXPECT_EQ(msg6, "");
1565}
1566
1573
1575{
1576 public:
1578 {
1579 events.push_back(event);
1580 }
1581
1582 std::vector<openvpn::ClientEvent::Base::Ptr> events;
1583};
1584
1585TEST(Proto, ClientProtoCheckCcMsg)
1586{
1587 asio::io_context io_context;
1588 ClientRandomAPI::Ptr rng_cli(new ClientRandomAPI());
1589 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1590 MySessionStats::Ptr cli_stats(new MySessionStats);
1591 Time time;
1592
1594 /* keep a reference to the right class to avoid repeated casted */
1595 EventQueueVector *eqv = dynamic_cast<EventQueueVector *>(eqv_ptr.get());
1596 /* check that the cast worked */
1597 ASSERT_TRUE(eqv);
1598
1599 MockCallback mockCB;
1602 frame,
1603 rng_cli,
1604 std::move(cli_stats),
1605 time);
1606 clisessconf.cli_events = std::move(eqv_ptr);
1607 openvpn::ClientProto::Session::Ptr clisession = new ClientProto::Session{io_context, clisessconf, &mockCB};
1608
1609 clisession->validate_and_post_cc_msg("valid message");
1610
1611
1612 EXPECT_TRUE(eqv->events.empty());
1613
1614 clisession->validate_and_post_cc_msg("invalid\nmessage");
1615 EXPECT_EQ(eqv->events.size(), 1);
1616 auto ev = eqv->events.back();
1617 auto uf = dynamic_cast<openvpn::ClientEvent::UnsupportedFeature *>(ev.get());
1618 /* check that the cast worked */
1619 ASSERT_TRUE(uf);
1620 EXPECT_EQ(uf->name, "Invalid chars in control message");
1621 EXPECT_EQ(uf->reason, "Control channel message with invalid characters not allowed to be send with post_cc_msg");
1622}
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)
bool verify_wkc_packets_fit(size_t max_size) const
void data_decrypt(const ProtoContext::PacketType &type, BufferAllocated &in_out)
void control_send(BufferPtr &&app_bp)
void data_encrypt(BufferAllocated &in_out)
std::vector< size_t > wkc_pkt_sizes_
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
size_t max_ctrl_pkt_size() const
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
size_t max_ctrl_pkt_size_
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_
const T * c_data() const
Returns a const pointer to the start of the buffer.
Definition buffer.hpp:1193
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
@ READ_BIO_MEMQ_STREAM
Definition frame.hpp:41
size_t prepare(const unsigned int context, Buffer &buf) const
Definition frame.hpp:263
const Time::Duration & slowest_handshake()
Definition proto.hpp:4484
const Time & now() const
Definition proto.hpp:4585
void flush(const bool control_channel)
Definition proto.hpp:4305
void control_send(BufferPtr &&app_bp)
Definition proto.hpp:4361
void data_encrypt(BufferAllocated &in_out)
Definition proto.hpp:4399
static void write_auth_string(const S &str, Buffer &buf)
Definition proto.hpp:1566
bool is_server() const
Definition proto.hpp:4609
bool data_decrypt(const PacketType &type, BufferAllocated &in_out)
Definition proto.hpp:4409
Error::Type invalidation_reason() const
Definition proto.hpp:4496
unsigned int negotiations() const
Definition proto.hpp:4478
Time next_housekeeping() const
Definition proto.hpp:4343
bool invalidated() const
Definition proto.hpp:4490
void reset(const ProtoSessionID cookie_psid=ProtoSessionID())
Resets ProtoContext *this to it's initial state.
Definition proto.hpp:4139
void start(const ProtoSessionID cookie_psid=ProtoSessionID())
Initialize the state machine and start protocol negotiation.
Definition proto.hpp:4268
const ProtoConfig & conf() const
Definition proto.hpp:4629
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
const std::string & tls_crypt_v2_key_fn
bool tls_version_mismatch
bool force_resend_wkc
bool use_tls_auth_with_tls_crypt_v2
size_t mssfix_ctrl
size_t control_payload
static const char config[]
#define TLS_TIMEOUT_CLIENT
#define TLS_TIMEOUT_SERVER
#define PROTO_DIGEST
int test_retry(const int n_retries, const struct proto_test &test_config)
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,...)