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_OPENSSL) || defined(USE_MBEDTLS))
177#error Must define one or more of USE_OPENSSL, USE_MBEDTLS.
178#endif
179
180#if defined(USE_OPENSSL) && defined(USE_MBEDTLS)
181#undef USE_OPENSSL
182#define USE_OPENSSL_SERVER
183#elif !defined(USE_OPENSSL) && defined(USE_MBEDTLS)
184#define USE_MBEDTLS_SERVER
185#elif defined(USE_OPENSSL) && !defined(USE_MBEDTLS)
186#define USE_OPENSSL_SERVER
187#else
188#error no server setup
189#endif
190
191#if defined(USE_OPENSSL) || defined(USE_OPENSSL_SERVER)
195#endif
196
197#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_SERVER)
201#include <mbedtls/debug.h>
202#endif
203
205
206using namespace openvpn;
207
208// server Crypto/SSL/Rand implementation
209#ifdef USE_MBEDTLS_SERVER
210typedef MbedTLSCryptoAPI ServerCryptoAPI;
211typedef MbedTLSContext ServerSSLAPI;
212typedef MbedTLSRandom ServerRandomAPI;
213#elif defined(USE_OPENSSL_SERVER)
214using ServerCryptoAPI = OpenSSLCryptoAPI;
215using ServerSSLAPI = OpenSSLContext;
216using ServerRandomAPI = OpenSSLRandom;
217#else
218#error No server SSL implementation defined
219#endif
220
221// client SSL implementation can be OpenSSL or MbedTLS
222#ifdef USE_MBEDTLS
223typedef MbedTLSCryptoAPI ClientCryptoAPI;
224typedef MbedTLSContext ClientSSLAPI;
225typedef MbedTLSRandom ClientRandomAPI;
226#elif defined(USE_OPENSSL)
227using ClientCryptoAPI = OpenSSLCryptoAPI;
228using ClientSSLAPI = OpenSSLContext;
229using ClientRandomAPI = OpenSSLRandom;
230#else
231#error No client SSL implementation defined
232#endif
233
234const char message[] = "Message _->_ 0000000000 It was a bright cold day in April, and the clocks\n"
235 "were striking thirteen. Winston Smith, his chin nuzzled\n"
236 "into his breast in an effort to escape the vile wind,\n"
237 "slipped quickly through the glass doors of Victory\n"
238 "Mansions, though not quickly enough to prevent a\n"
239 "swirl of gritty dust from entering along with him.\n"
240#ifdef LARGE_MESSAGE
241 "It was a bright cold day in April, and the clocks\n"
242 "were striking thirteen. Winston Smith, his chin nuzzled\n"
243 "into his breast in an effort to escape the vile wind,\n"
244 "slipped quickly through the glass doors of Victory\n"
245 "Mansions, though not quickly enough to prevent a\n"
246 "swirl of gritty dust from entering along with him.\n"
247 "It was a bright cold day in April, and the clocks\n"
248 "were striking thirteen. Winston Smith, his chin nuzzled\n"
249 "into his breast in an effort to escape the vile wind,\n"
250 "slipped quickly through the glass doors of Victory\n"
251 "Mansions, though not quickly enough to prevent a\n"
252 "swirl of gritty dust from entering along with him.\n"
253 "It was a bright cold day in April, and the clocks\n"
254 "were striking thirteen. Winston Smith, his chin nuzzled\n"
255 "into his breast in an effort to escape the vile wind,\n"
256 "slipped quickly through the glass doors of Victory\n"
257 "Mansions, though not quickly enough to prevent a\n"
258 "swirl of gritty dust from entering along with him.\n"
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#endif
266 ;
267
268// A "Drought" measures the maximum period of time between
269// any two successive events. Used to measure worst-case
270// packet loss.
272{
273 public:
274 OPENVPN_SIMPLE_EXCEPTION(drought_limit_exceeded);
275
276 DroughtMeasure(const std::string &name_arg, TimePtr now_arg)
277 : now(now_arg), name(name_arg)
278 {
279 }
280
281 void event()
282 {
283 if (last_event.defined())
284 {
285 Time::Duration since_last = *now - last_event;
286 if (since_last > drought)
287 {
288 drought = since_last;
289#if defined(VERBOSE) || defined(DROUGHT_LIMIT)
290 {
291 const unsigned int r = drought.raw();
292#if defined(VERBOSE)
293 std::cout << "*** Drought " << name << " has reached " << r << "\n";
294#endif
295#ifdef DROUGHT_LIMIT
296 if (r > DROUGHT_LIMIT)
297 throw drought_limit_exceeded();
298#endif
299 }
300#endif
301 }
302 }
303 last_event = *now;
304 }
305
306 Time::Duration operator()() const
307 {
308 return drought;
309 }
310
311 private:
314 Time::Duration drought;
315 std::string name;
316};
317
318// test the OpenVPN protocol implementation in ProtoContext
320{
321 /* Callback methods that are not used */
322 void active(bool primary) override
323 {
324 }
325
326 bool supports_epoch_data() override
327 {
328 return true;
329 }
330
331 public:
332 OPENVPN_EXCEPTION(session_invalidated);
333
335 const SessionStats::Ptr &stats)
336 : proto_context(this, config, stats),
337 control_drought("control", config->now),
338 data_drought("data", config->now),
340 {
341 // zero progress value
342 std::memset(progress_, 0, 11);
343 }
344
345 void reset()
346 {
347 net_out.clear();
348 wkc_pkt_sizes_.clear();
352 }
353
354 void initial_app_send(const char *msg)
355 {
357 const size_t msglen = std::strlen(msg) + 1;
358 BufferAllocated app_buf((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
359 copy_progress(app_buf);
360 control_send(std::move(app_buf));
361 proto_context.flush(true);
362 }
363
364 void app_send_templ_init(const char *msg)
365 {
367 const size_t msglen = std::strlen(msg) + 1;
368 templ = BufferAllocatedRc::Create((unsigned char *)msg, msglen, BufAllocFlags::NO_FLAGS);
369 proto_context.flush(true);
370 }
371
373 {
374#if !FEEDBACK
375 if (bool(iteration++ & 1) == is_server())
376 {
377 modmsg(templ);
378 BufferAllocated app_buf(*templ);
379 control_send(std::move(app_buf));
380 flush(true);
382 }
383#endif
384 }
385
387 {
389 {
391 return true;
392 }
393 return false;
394 }
395
396 void control_send(BufferPtr &&app_bp)
397 {
398 app_bytes_ += app_bp->size();
399 proto_context.control_send(std::move(app_bp));
400 }
401
403 {
404 app_bytes_ += app_buf.size();
405 proto_context.control_send(std::move(app_buf));
406 }
407
409 {
412 bp->write((unsigned char *)str, std::strlen(str));
413 data_encrypt(*bp);
414 return bp;
415 }
416
418 {
420 }
421
423 {
424 proto_context.data_decrypt(type, in_out);
425 if (!in_out.empty())
426 {
427 data_bytes_ += in_out.size();
429 }
430 }
431
432 size_t net_bytes() const
433 {
434 return net_bytes_;
435 }
436 size_t app_bytes() const
437 {
438 return app_bytes_;
439 }
440 size_t data_bytes() const
441 {
442 return data_bytes_;
443 }
444 size_t n_control_recv() const
445 {
446 return n_control_recv_;
447 }
448 size_t n_control_send() const
449 {
450 return n_control_send_;
451 }
452
453 const char *progress() const
454 {
455 return progress_;
456 }
457
458 void finalize()
459 {
462 }
463
465 {
467 throw session_invalidated(Error::name(proto_context.invalidation_reason()));
468 }
469
471 {
472 disable_xmit_ = true;
473 }
474
476
477 std::deque<BufferPtr> net_out;
478
479 // sizes of the CONTROL_WKC_V1 packets (the tls-crypt-v2 WKc riders)
480 // emitted via control_net_send(). Only these are recorded, so the
481 // vector stays tiny even across the long feedback tests.
482 std::vector<size_t> wkc_pkt_sizes_;
483
484 // largest control channel packet emitted via control_net_send()
486
487 size_t max_ctrl_pkt_size() const
488 {
489 return max_ctrl_pkt_size_;
490 }
491
492 // Verify every emitted CONTROL_WKC_V1 packet fits within max_size,
493 // and that at least one such packet was emitted.
494 bool verify_wkc_packets_fit(size_t max_size) const
495 {
496 if (wkc_pkt_sizes_.empty())
497 {
498 std::cerr << "no CONTROL_WKC_V1 packet was emitted by the client\n";
499 return false;
500 }
501 for (const size_t size : wkc_pkt_sizes_)
502 {
503 if (size > max_size)
504 {
505 std::cerr << "CONTROL_WKC_V1 packet too large: " << size
506 << " > " << max_size << '\n';
507 return false;
508 }
509 }
510 return true;
511 }
512
515
516 private:
517 void control_net_send(const Buffer &net_buf) override
518 {
519 if (disable_xmit_)
520 return;
521 net_bytes_ += net_buf.size();
522 max_ctrl_pkt_size_ = std::max(max_ctrl_pkt_size_, net_buf.size());
523 if (net_buf.size()
525 wkc_pkt_sizes_.push_back(net_buf.size());
527 }
528
529 void control_recv(BufferPtr &&app_bp) override
530 {
532 work.swap(app_bp);
533 if (work->size() >= 23)
534 std::memcpy(progress_, work->data() + 13, 10);
535
536#ifdef VERBOSE
537 {
538 const ssize_t trunc = 64;
539 const std::string show((char *)work->data(), trunc);
540 std::cout << now().raw() << " " << mode().str() << " " << show << "\n";
541 }
542#endif
543#if FEEDBACK
544 modmsg(work);
545 control_send(std::move(work));
546#endif
549 }
550
552 {
553 if (progress_[0]) // make sure progress was initialized
554 std::memcpy(buf.data() + 13, progress_, 10);
555 }
556
557 void modmsg(BufferPtr &buf)
558 {
559 char *msg = (char *)buf->data();
561 {
562 msg[8] = 'S';
563 msg[11] = 'C';
564 }
565 else
566 {
567 msg[8] = 'C';
568 msg[11] = 'S';
569 }
570
571 // increment embedded number
572 for (int i = 22; i >= 13; i--)
573 {
574 if (msg[i] != '9')
575 {
576 msg[i]++;
577 break;
578 }
579 msg[i] = '0';
580 }
581 }
582
584 size_t app_bytes_ = 0;
585 size_t net_bytes_ = 0;
586 size_t data_bytes_ = 0;
587 size_t n_control_send_ = 0;
588 size_t n_control_recv_ = 0;
590#if !FEEDBACK
591 size_t iteration = 0;
592#endif
593 char progress_[11];
594 bool disable_xmit_ = false;
595};
596
598{
600
601 public:
603 const SessionStats::Ptr &stats)
604 : TestProto(config, stats)
605 {
606 }
607
608 private:
609 void client_auth(Buffer &buf) override
610 {
611 const std::string username("foo");
612 const std::string password("bar");
613 ProtoContext::write_auth_string(username, buf);
614 ProtoContext::write_auth_string(password, buf);
615 }
616};
617
619{
620
621 public:
622 void start()
623 {
625 }
626
628
629
631 const SessionStats::Ptr &stats)
632 : TestProto(config, stats)
633 {
634 }
635
636 private:
637 void server_auth(const std::string &username,
638 const SafeString &password,
639 const std::string &peer_info,
640 const AuthCert::Ptr &auth_cert) override
641 {
642#ifdef VERBOSE
643 std::cout << "**** AUTHENTICATE " << username << '/' << password << " PEER INFO:\n";
644 std::cout << peer_info;
645#endif
646 if (username != "foo" || password != "bar")
647 throw auth_failed();
648 }
649};
650
651// Simulate a noisy transmission channel where packets can be dropped,
652// reordered, or corrupted.
654{
655 public:
656 NoisyWire(const std::string &title_arg,
657 TimePtr now_arg,
658 RandomAPI &rand_arg,
659 const unsigned int reorder_prob_arg,
660 const unsigned int drop_prob_arg,
661 const unsigned int corrupt_prob_arg)
662 : title(title_arg),
663#ifdef VERBOSE
664 now(now_arg),
665#endif
666 random(rand_arg),
667 reorder_prob(reorder_prob_arg),
668 drop_prob(drop_prob_arg),
669 corrupt_prob(corrupt_prob_arg)
670 {
671 }
672
673 template <typename T1, typename T2>
674 void xfer(T1 &a, T2 &b)
675 {
676 // check for errors
677 a.check_invalidated();
678 b.check_invalidated();
679
680 // need to retransmit?
681 if (a.do_housekeeping())
682 {
683#ifdef VERBOSE
684 std::cout << now->raw() << " " << title << " Housekeeping\n";
685#endif
686 }
687
688 // queue a control channel packet
689 a.app_send_templ();
690
691 // queue a data channel packet
692 if (a.proto_context.data_channel_ready())
693 {
694 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...");
695 wire.push_back(bp);
696 }
697
698 // transfer network packets from A -> wire
699 while (!a.net_out.empty())
700 {
701 BufferPtr bp = a.net_out.front();
702#ifdef VERBOSE
703 std::cout << now->raw() << " " << title << " " << a.dump_packet(*bp) << "\n";
704#endif
705 a.net_out.pop_front();
706 wire.push_back(bp);
707 }
708
709 // transfer network packets from wire -> B
710 while (true)
711 {
712 BufferPtr bp = recv();
713 if (!bp)
714 break;
715 typename ProtoContext::PacketType pt = b.proto_context.packet_type(*bp);
716 if (pt.is_control())
717 {
718#ifdef VERBOSE
719 if (!b.control_net_validate(pt, *bp)) // not strictly necessary since control_net_recv will also validate
720 std::cout << now->raw() << " " << title << " CONTROL PACKET VALIDATION FAILED\n";
721#endif
722 b.proto_context.control_net_recv(pt, std::move(bp));
723 }
724 else if (pt.is_data())
725 {
726 try
727 {
728 b.data_decrypt(pt, *bp);
729#ifdef VERBOSE
730 if (bp->size())
731 {
732 const std::string show((char *)bp->data(), std::min(bp->size(), size_t(40)));
733 std::cout << now->raw() << " " << title << " DATA CHANNEL DECRYPT: " << show << "\n";
734 }
735#endif
736 }
737 catch ([[maybe_unused]] const std::exception &e)
738 {
739#ifdef VERBOSE
740 std::cout << now->raw() << " " << title << " Exception on data channel decrypt: " << e.what() << "\n";
741#endif
742 }
743 }
744 else
745 {
746#ifdef VERBOSE
747 std::cout << now->raw() << " " << title << " KEY_STATE_ERROR\n";
748#endif
749 b.proto_context.stat().error(Error::KEY_STATE_ERROR);
750 }
751
752#ifdef SIMULATE_UDP_AMPLIFY_ATTACK
753 if (b.proto_context.is_state_client_wait_reset_ack())
754 {
755 b.disable_xmit();
756#ifdef VERBOSE
757 std::cout << now->raw() << " " << title << " SIMULATE_UDP_AMPLIFY_ATTACK disable client xmit\n";
758#endif
759 }
760#endif
761 }
762 b.proto_context.flush(true);
763 }
764
765 private:
767 {
768#ifdef SIMULATE_OOO
769 // simulate packets being received out of order
770 if (wire.size() >= 2 && !rand(reorder_prob))
771 {
772 const size_t i = random.randrange(wire.size() - 1) + 1;
773#ifdef VERBOSE
774 std::cout << now->raw() << " " << title << " Simulating packet reordering " << i << " -> 0\n";
775#endif
776 std::swap(wire[0], wire[i]);
777 }
778#endif
779
780 if (!wire.empty())
781 {
782 BufferPtr bp = wire.front();
783 wire.pop_front();
784
785#ifdef VERBOSE
786 std::cout << now->raw() << " " << title << " Received packet, size=" << bp->size() << "\n";
787#endif
788
789#ifdef SIMULATE_DROPPED
790 // simulate dropped packet
791 if (!rand(drop_prob))
792 {
793#ifdef VERBOSE
794 std::cout << now->raw() << " " << title << " Simulating a dropped packet\n";
795#endif
796 return BufferPtr();
797 }
798#endif
799
800#ifdef SIMULATE_CORRUPTED
801 // simulate corrupted packet
802 if (!bp->empty() && !rand(corrupt_prob))
803 {
804#ifdef VERBOSE
805 std::cout << now->raw() << " " << title << " Simulating a corrupted packet\n";
806#endif
807 const size_t pos = random.randrange(bp->size());
808 const unsigned char value = random.randrange(std::numeric_limits<unsigned char>::max());
809 (*bp)[pos] = value;
810 }
811#endif
812 return bp;
813 }
814
815 return BufferPtr();
816 }
817
818 unsigned int rand(const unsigned int prob)
819 {
820 if (prob)
821 return random.randrange(prob);
822 return 1;
823 }
824
825 std::string title;
826#ifdef VERBOSE
827 TimePtr now;
828#endif
830 unsigned int reorder_prob;
831 unsigned int drop_prob;
832 unsigned int corrupt_prob;
833 std::deque<BufferPtr> wire;
834};
835
836class MySessionStats : public SessionStats
837{
838 public:
840
842 {
843 std::memset(errors, 0, sizeof(errors));
844 }
845
846 void error(const size_t err_type, const std::string *text = nullptr) override
847 {
848 if (err_type < Error::N_ERRORS)
849 ++errors[err_type];
850 }
851
853 {
854 if (type < Error::N_ERRORS)
855 return errors[type];
856 return 0;
857 }
858
859 void show_error_counts() const
860 {
861 for (size_t i = 0; i < Error::N_ERRORS; ++i)
862 {
863 count_t c = errors[i];
864 if (c)
865 std::cerr << Error::name(i) << " : " << c << '\n';
866 }
867 }
868
869 private:
871};
872
877static auto create_client_ssl_config(Frame::Ptr frame, ClientRandomAPI::Ptr rng, bool tls_version_mismatch = false)
878{
879 const std::string client_crt = read_text(TEST_KEYCERT_DIR "client.crt");
880 const std::string client_key = read_text(TEST_KEYCERT_DIR "client.key");
881 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
882
883 // client config
884 ClientSSLAPI::Config::Ptr cc(new ClientSSLAPI::Config());
885 cc->set_mode(Mode(Mode::CLIENT));
886 cc->set_frame(frame);
887 cc->set_rng(rng);
888 cc->load_ca(ca_crt, true);
889 cc->load_cert(client_crt);
890 cc->load_private_key(client_key);
891 if (tls_version_mismatch)
892 cc->set_tls_version_max(TLSVersion::Type::V1_2);
893 else
894 cc->set_tls_version_min(TLS_VER_MIN);
895#ifdef VERBOSE
896 cc->set_debug_level(1);
897#endif
898 return cc;
899}
900
901static auto create_client_proto_context(ClientSSLAPI::Config::Ptr cc,
902 Frame::Ptr frame,
903 ClientRandomAPI::Ptr rng,
904 MySessionStats::Ptr cli_stats,
905 Time &time,
906 const std::string &tls_crypt_v2_key_fn = "",
907 bool tls_auth_only = false,
908 bool use_dynamic_tls_crypt = false)
909{
910 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
911 const std::string tls_crypt_v2_client_key = tls_crypt_v2_key_fn.empty()
912 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-client.key")
913 : read_text(TEST_KEYCERT_DIR + tls_crypt_v2_key_fn);
914
915 // client ProtoContext config
916 using ClientProtoContext = ProtoContext;
917 ClientProtoContext::ProtoConfig::Ptr cp(new ClientProtoContext::ProtoConfig);
918 cp->ssl_factory = cc->new_factory();
919 CryptoAlgs::allow_default_dc_algs<ClientCryptoAPI>(cp->ssl_factory->libctx(), false, false);
920 cp->dc.set_factory(new CryptoDCSelect<ClientCryptoAPI>(cp->ssl_factory->libctx(), frame, cli_stats, rng));
921 cp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ClientCryptoAPI>());
922 cp->frame = std::move(frame);
923 cp->now = &time;
924 cp->rng = rng;
925 cp->prng = rng;
926 cp->protocol = Protocol(Protocol::UDPv4);
927 cp->layer = Layer(Layer::OSI_LAYER_3);
928#ifdef PROTOv2
929 cp->enable_op32 = true;
930 cp->remote_peer_id = 100;
931#endif
932 cp->comp_ctx = CompressContext(COMP_METH, false);
933 cp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
934 cp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
935
936#ifdef USE_TLS_AUTH
937 cp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ClientCryptoAPI>());
938 cp->tls_auth_key.parse(tls_auth_key);
939 cp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
940 cp->key_direction = 0;
941#endif
942#ifdef USE_TLS_CRYPT
943 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
944 cp->tls_crypt_key.parse(tls_auth_key);
945 cp->set_tls_crypt_algs();
946 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
947#endif
948#ifdef USE_TLS_CRYPT_V2
949 if (tls_auth_only)
950 {
951 // A plain tls-auth client, for testing a server that holds a tls-crypt-v2 key as
952 // well: such a session must stay in TLS_AUTH mode from end to end.
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 }
958 else
959 {
960 cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
961 cp->set_tls_crypt_algs();
962 {
963 TLSCryptV2ClientKey tls_crypt_v2_key(cp->tls_crypt_context);
964 tls_crypt_v2_key.parse(tls_crypt_v2_client_key);
965 tls_crypt_v2_key.extract_key(cp->tls_crypt_key);
966 tls_crypt_v2_key.extract_wkc(cp->wkc);
967 }
968 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
969 }
970 if (use_dynamic_tls_crypt)
971 cp->enable_dynamic_tls_crypt();
972#endif
973#ifdef HANDSHAKE_WINDOW
974 cp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
975#elif SITER > 1
976 cp->handshake_window = Time::Duration::seconds(30);
977#else
978 cp->handshake_window = Time::Duration::seconds(18); // will cause a small number of handshake failures
979#endif
980#ifdef BECOME_PRIMARY_CLIENT
981 cp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_CLIENT);
982#else
983 cp->become_primary = cp->handshake_window;
984#endif
985 cp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_CLIENT);
986#ifdef CLIENT_NO_RENEG
987 cp->renegotiate = Time::Duration::infinite();
988#else
989 cp->renegotiate = Time::Duration::seconds(RENEG);
990#endif
991 cp->expire = cp->renegotiate + cp->renegotiate;
992 cp->keepalive_ping = Time::Duration::seconds(5);
993 cp->keepalive_timeout = Time::Duration::seconds(60);
994 cp->keepalive_timeout_early = cp->keepalive_timeout;
995
996#ifdef VERBOSE
997 std::cout << "CLIENT OPTIONS: " << cp->options_string() << "\n";
998 std::cout << "CLIENT PEER INFO:\n";
999 std::cout << cp->peer_info_string();
1000#endif
1001 return cp;
1002}
1003
1004// Configures one specific test run */
1006{
1007 bool use_tls_ekm = false;
1009 const std::string &tls_crypt_v2_key_fn = "";
1013 bool force_resend_wkc = false;
1015 size_t control_payload = 378;
1016 size_t mssfix_ctrl = 0;
1017};
1018
1019// execute the unit test in one thread
1020int test(const struct proto_test &t)
1021{
1022 try
1023 {
1024 // frame
1025 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1026 // Shrink only the control-channel ciphertext context, mirroring what
1027 // mssfix-ctrl does in production (see frame_init()): the cleartext
1028 // staging buffers (e.g. WRITE_SSL_CLEARTEXT, used for the auth
1029 // message) keep their normal size.
1031
1032 // RNG
1033 ClientRandomAPI::Ptr prng_cli(new ClientRandomAPI());
1034 ServerRandomAPI::Ptr prng_serv(new ServerRandomAPI());
1035 MTRand rng_noncrypto;
1036
1037 // init simulated time
1038 Time time;
1039 const Time::Duration time_step = Time::Duration::binary_ms(100);
1040
1041 // config files
1042 const std::string ca_crt = read_text(TEST_KEYCERT_DIR "ca.crt");
1043 const std::string server_crt = read_text(TEST_KEYCERT_DIR "server.crt");
1044 const std::string server_key = read_text(TEST_KEYCERT_DIR "server.key");
1045 const std::string dh_pem = read_text(TEST_KEYCERT_DIR "dh.pem");
1046 const std::string tls_auth_key = read_text(TEST_KEYCERT_DIR "tls-auth.key");
1047 const std::string tls_crypt_v2_server_key = t.tls_crypt_v2_key_fn.empty()
1048 ? read_text(TEST_KEYCERT_DIR "tls-crypt-v2-server.key")
1049 : "";
1050
1051 // client config
1052 ClientSSLAPI::Config::Ptr cc = create_client_ssl_config(frame, prng_cli, t.tls_version_mismatch);
1053 MySessionStats::Ptr cli_stats(new MySessionStats);
1054
1055 auto cp = create_client_proto_context(std::move(cc), frame, prng_cli, cli_stats, time, t.tls_crypt_v2_key_fn, t.client_tls_auth_only, t.use_dynamic_tls_crypt);
1056 if (t.use_tls_ekm)
1057 cp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1058 if (t.mssfix_ctrl)
1059 cp->mssfix_ctrl = t.mssfix_ctrl;
1060
1061 // server config
1062 MySessionStats::Ptr serv_stats(new MySessionStats);
1063
1064 ServerSSLAPI::Config::Ptr sc(new ClientSSLAPI::Config());
1065 sc->set_mode(Mode(Mode::SERVER));
1066 sc->set_frame(frame);
1067 sc->set_rng(prng_serv);
1068 sc->load_ca(ca_crt, true);
1069 sc->load_cert(server_crt);
1070 sc->load_private_key(server_key);
1071 sc->load_dh(dh_pem);
1072 sc->set_tls_version_min(t.tls_version_mismatch ? TLSVersion::Type::V1_3 : TLS_VER_MIN);
1073#ifdef VERBOSE
1074 sc->set_debug_level(1);
1075#endif
1076
1077 // server ProtoContext config
1078 using ServerProtoContext = ProtoContext;
1079 ServerProtoContext::ProtoConfig::Ptr sp(new ServerProtoContext::ProtoConfig);
1080 sp->ssl_factory = sc->new_factory();
1081 sp->dc.set_factory(new CryptoDCSelect<ServerCryptoAPI>(sp->ssl_factory->libctx(), frame, serv_stats, prng_serv));
1082 sp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ServerCryptoAPI>());
1083 sp->frame = frame;
1084 sp->now = &time;
1085 sp->rng = prng_serv;
1086 sp->prng = prng_serv;
1087 sp->protocol = Protocol(Protocol::UDPv4);
1088 sp->layer = Layer(Layer::OSI_LAYER_3);
1089#ifdef PROTOv2
1090 sp->enable_op32 = true;
1091 sp->remote_peer_id = 101;
1092#endif
1093 sp->comp_ctx = CompressContext(COMP_METH, false);
1094 sp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
1095 sp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1096 if (t.use_tls_ekm)
1097 sp->dc.set_key_derivation(CryptoAlgs::KeyDerivation::TLS_EKM);
1098#ifdef USE_TLS_AUTH
1099 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1100 sp->tls_auth_key.parse(tls_auth_key);
1101 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1102 sp->key_direction = 1;
1103#endif
1104#ifdef USE_TLS_CRYPT
1105 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1106 sp->tls_crypt_key.parse(tls_auth_key);
1107 sp->set_tls_crypt_algs();
1108 cp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V1;
1109#endif
1110#ifdef USE_TLS_CRYPT_V2
1111 sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1112
1113 if (t.tls_crypt_v2_key_fn.empty())
1114 {
1115 TLSCryptV2ServerKey tls_crypt_v2_key;
1116 tls_crypt_v2_key.parse(tls_crypt_v2_server_key);
1117 tls_crypt_v2_key.extract_key(sp->tls_crypt_key);
1118 }
1119
1120 sp->set_tls_crypt_algs();
1121 sp->tls_crypt_metadata_factory.reset(new CryptoTLSCryptMetadataFactory());
1122 sp->tls_crypt_ = ProtoContext::ProtoConfig::TLSCrypt::V2;
1123 sp->tls_crypt_v2_serverkey_id = !t.tls_crypt_v2_key_fn.empty();
1124 sp->tls_crypt_v2_serverkey_dir = TEST_KEYCERT_DIR;
1125
1127 sp->enable_dynamic_tls_crypt();
1128
1130 {
1131 sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
1132 sp->tls_auth_key.parse(tls_auth_key);
1133 sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
1134 sp->key_direction = 1;
1135 }
1136#endif
1137#ifdef HANDSHAKE_WINDOW
1138 sp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
1139#elif SITER > 1
1140 sp->handshake_window = Time::Duration::seconds(30);
1141#else
1142 sp->handshake_window = Time::Duration::seconds(17) + Time::Duration::binary_ms(512);
1143#endif
1144#ifdef BECOME_PRIMARY_SERVER
1145 sp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_SERVER);
1146#else
1147 sp->become_primary = sp->handshake_window;
1148#endif
1149 sp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_SERVER);
1150#ifdef SERVER_NO_RENEG
1151 sp->renegotiate = Time::Duration::infinite();
1152#else
1153 // NOTE: if we don't add sp->handshake_window, both client and server reneg-sec (RENEG)
1154 // will be equal and will therefore occasionally collide. Such collisions can sometimes
1155 // produce this OpenSSL error:
1156 // OpenSSLContext::SSL::read_cleartext: BIO_read failed, cap=400 status=-1: error:140E0197:SSL routines:SSL_shutdown:shutdown while in init
1157 // The issue was introduced by this patch in OpenSSL:
1158 // https://github.com/openssl/openssl/commit/64193c8218540499984cd63cda41f3cd491f3f59
1159 sp->renegotiate = Time::Duration::seconds(RENEG) + sp->handshake_window;
1160#endif
1161 sp->expire = sp->renegotiate + sp->renegotiate;
1162 sp->keepalive_ping = Time::Duration::seconds(5);
1163 sp->keepalive_timeout = Time::Duration::seconds(60);
1164 sp->keepalive_timeout_early = Time::Duration::seconds(10);
1165
1166#ifdef VERBOSE
1167 std::cout << "SERVER OPTIONS: " << sp->options_string() << "\n";
1168 std::cout << "SERVER PEER INFO:\n";
1169 std::cout << sp->peer_info_string();
1170#endif
1171
1172 TestProtoClient cli_proto(cp, cli_stats);
1173 TestProtoServer serv_proto(sp, serv_stats);
1174
1175 for (int i = 0; i < SITER; ++i)
1176 {
1177#ifdef VERBOSE
1178 std::cout << "***** SITER " << i << "\n";
1179#endif
1180 cli_proto.reset();
1181 serv_proto.reset();
1182
1183 NoisyWire client_to_server("Client -> Server", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1184 NoisyWire server_to_client("Server -> Client", &time, rng_noncrypto, 8, 16, 32); // last value: 32
1185
1186 int j = -1;
1187 try
1188 {
1189#if FEEDBACK
1190 // start feedback loop
1191 cli_proto.initial_app_send(message);
1192 serv_proto.start();
1193#else
1194 cli_proto.app_send_templ_init(message);
1195 serv_proto.app_send_templ_init(message);
1196#endif
1197
1198 if (t.spoof_hard_reset_v3)
1199 {
1200 // What an off-path attacker can put on the wire: a
1201 // CONTROL_HARD_RESET_CLIENT_V3 opcode over garbage.
1202 // packet_type() weighs the opcode and the key id and nothing
1203 // else, so this reaches decapsulate() and asks a tls-auth
1204 // server to make itself a tls-crypt-v2 one. Nothing in it
1205 // authenticates, so the handshake below must still run its
1206 // course.
1209 for (size_t k = 0; k < 64; ++k)
1210 bp->push_back(static_cast<unsigned char>(k));
1211
1212 const ProtoContext::PacketType pt = serv_proto.proto_context.packet_type(*bp);
1213 if (!pt.is_control())
1214 return 1;
1215 serv_proto.proto_context.control_net_recv(pt, std::move(bp));
1216 }
1217
1218 if (t.force_resend_wkc)
1219 {
1220 // Pretend the server asked the client to resend the
1221 // tls-crypt-v2 WKc on the first control packet, so the
1222 // client's ClientHello is emitted as CONTROL_WKC_V1 with
1223 // the WKc appended -- as is every retransmission of that
1224 // packet, which the noisy wire below produces plenty of.
1225 // The server has to take the WKc off each of them, so the
1226 // handshake completes like any other.
1227 cli_proto.proto_context.force_resend_wkc();
1228 }
1229
1230 // message loop
1231 for (j = 0; j < ITER; ++j)
1232 {
1233 client_to_server.xfer(cli_proto, serv_proto);
1234 server_to_client.xfer(serv_proto, cli_proto);
1235 time += time_step;
1236 }
1237
1238 if (t.force_resend_wkc)
1239 {
1240 // Frame control context above is Context(128, control_payload, ...).
1241 // Even the WKc-bearing packet must stay within headroom +
1242 // payload; without the reservation fix it overflows by
1243 // ~wkc.size() bytes.
1244 if (!cli_proto.verify_wkc_packets_fit(128 + t.control_payload))
1245 return 1;
1246 // when a wire cap is configured, every emitted control
1247 // packet must stay within it after all wrappings
1248 if (t.mssfix_ctrl && cli_proto.max_ctrl_pkt_size() > t.mssfix_ctrl)
1249 {
1250 std::cerr << "control packet exceeded mssfix_ctrl: "
1251 << cli_proto.max_ctrl_pkt_size()
1252 << " > " << t.mssfix_ctrl << '\n';
1253 return 1;
1254 }
1255 }
1256 }
1257 catch (const std::exception &e)
1258 {
1259 std::cerr << "Exception[" << i << '/' << j << "]: " << e.what() << '\n';
1260 return 1;
1261 }
1262 }
1263
1264 cli_proto.finalize();
1265 serv_proto.finalize();
1266
1267 const size_t ab = cli_proto.app_bytes() + serv_proto.app_bytes();
1268 const size_t nb = cli_proto.net_bytes() + serv_proto.net_bytes();
1269 const size_t db = cli_proto.data_bytes() + serv_proto.data_bytes();
1270
1271 std::cerr << "*** app bytes=" << ab
1272 << " net_bytes=" << nb
1273 << " data_bytes=" << db
1274 << " prog=" << cli_proto.progress() << '/' << serv_proto.progress()
1275#if !FEEDBACK
1276 << " CTRL=" << cli_proto.n_control_recv() << '/' << cli_proto.n_control_send() << '/' << serv_proto.n_control_recv() << '/' << serv_proto.n_control_send()
1277#endif
1278 << " D=" << cli_proto.control_drought().raw() << '/' << cli_proto.data_drought().raw() << '/' << serv_proto.control_drought().raw() << '/' << serv_proto.data_drought().raw()
1279 << " N=" << cli_proto.proto_context.negotiations() << '/' << serv_proto.proto_context.negotiations()
1280 << " SH=" << cli_proto.proto_context.slowest_handshake().raw() << '/' << serv_proto.proto_context.slowest_handshake().raw()
1281 << " HE=" << cli_stats->get_error_count(Error::HANDSHAKE_TIMEOUT) << '/' << serv_stats->get_error_count(Error::HANDSHAKE_TIMEOUT)
1282 << '\n';
1283
1285 {
1286 // The rekey is the first thing to use the derived key, and it is a control
1287 // channel handshake like any other: if the two ends derived different keys,
1288 // nothing either sends can authenticate and neither gets past its first one.
1289 if (cli_proto.proto_context.negotiations() < 2 || serv_proto.proto_context.negotiations() < 2)
1290 {
1291 std::cerr << "dynamic tls-crypt: no rekey completed\n";
1292 return 1;
1293 }
1294 }
1295
1296#ifdef STATS
1297 std::cerr << "-------- CLIENT STATS --------\n";
1298 cli_stats->show_error_counts();
1299 std::cerr << "-------- SERVER STATS --------\n";
1300 serv_stats->show_error_counts();
1301#endif
1302#ifdef OPENVPN_MAX_DATALIMIT_BYTES
1303 std::cerr << "------------------------------\n";
1304 std::cerr << "MAX_DATALIMIT_BYTES=" << DataLimit::max_bytes() << "\n";
1305#endif
1306 }
1307 catch (const std::exception &e)
1308 {
1309 std::cerr << "Exception: " << e.what() << '\n';
1310 return 1;
1311 }
1312 return 0;
1313}
1314
1315int test_retry(const int n_retries, const struct proto_test &test_config)
1316{
1317 int ret = 1;
1318 for (int i = 0; i < n_retries; ++i)
1319 {
1320 ret = test(test_config);
1321 if (!ret)
1322 return 0;
1323 std::cout << "Retry " << (i + 1) << '/' << n_retries << '\n';
1324 }
1325 std::cout << "Failed\n";
1326 return ret;
1327}
1328
1329class ProtoUnitTest : public testing::Test
1330{
1331 // Sets up the test fixture.
1332 void SetUp() override
1333 {
1334#ifdef USE_MBEDTLS
1335 mbedtls_debug_set_threshold(1);
1336#endif
1337
1339
1340#ifdef PROTO_VERBOSE
1342#else
1344#endif
1345 }
1346
1347 // Tears down the test fixture.
1348 void TearDown() override
1349 {
1350#ifdef USE_MBEDTLS
1351 mbedtls_debug_set_threshold(4);
1352#endif
1355 }
1356};
1357
1358TEST_F(ProtoUnitTest, BaseSingleThreadTlsEkm)
1359{
1360 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1361 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1362
1363 int ret = 0;
1364
1365 ret = test_retry(N_RETRIES, {.use_tls_ekm = true});
1366
1367 EXPECT_EQ(ret, 0);
1368}
1369
1370TEST_F(ProtoUnitTest, BaseSingleThreadNoTlsEkm)
1371{
1372 int ret = 0;
1373
1374 ret = test_retry(N_RETRIES, {.use_tls_ekm = false});
1375
1376 EXPECT_EQ(ret, 0);
1377}
1378
1379// Our mbedtls currently has a no-op set_tls_version_max() implementation,
1380// so we can't set mismatched client and server TLS versions.
1381// For now, just test this for OPENSSL which is full-featured.
1382#ifdef USE_OPENSSL
1383TEST_F(ProtoUnitTest, BaseSingleThreadTlsVersionMismatch)
1384{
1385 int ret = test({.tls_version_mismatch = true});
1386 EXPECT_NE(ret, 0);
1387}
1388#endif
1389
1390#ifdef USE_TLS_CRYPT_V2
1391TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithEmbeddedServerkey)
1392{
1393 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key"});
1394 EXPECT_EQ(ret, 0);
1395}
1396
1397TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithMissingEmbeddedServerkey)
1398{
1399 int ret = test({.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-missing-serverkey.key"});
1400 EXPECT_NE(ret, 0);
1401}
1402
1403TEST_F(ProtoUnitTest, BaseSingleThreadTlsCryptV2WithTlsAuthAlsoActive)
1404{
1405 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});
1406 EXPECT_EQ(ret, 0);
1407}
1408
1409// A server holding both keys becomes a tls-crypt-v2 one on the say-so of an opcode, which
1410// costs an off-path attacker one forged datagram. Here the client is a plain tls-auth one,
1411// so the session must stay in TLS_AUTH mode however loudly the forgery asks otherwise:
1412// before the wrap mode was taken back, the spoofed packet left the server unable to
1413// authenticate anything the real client went on to send.
1414TEST_F(ProtoUnitTest, TlsAuthSessionSurvivesSpoofedTlsCryptV2Opcode)
1415{
1416 int ret = test_retry(N_RETRIES,
1417 {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key",
1418 .use_tls_auth_with_tls_crypt_v2 = true,
1419 .client_tls_auth_only = true,
1420 .spoof_hard_reset_v3 = true});
1421 EXPECT_EQ(ret, 0);
1422}
1423
1424// Dynamic tls-crypt rekeys the control channel with a key each end derives from the TLS
1425// session -- so it needs keying material export, which our mbed TLS does not have -- and
1426// mixes its own tls-crypt key into. A tls-crypt-v2 server's ProtoConfig holds
1427// the server key it unwraps WKc's with, not the Kc inside them, so mixing that in derived a
1428// key the client could not match and the rekey never completed. Both server key modes are
1429// covered: with a server key in the config the server mixed in the wrong key, and with
1430// serverkey_id it had none to mix in and skipped the step the client had taken.
1431TEST_F(ProtoUnitTest, DynamicTlsCryptRekeysTlsCryptV2WithServerkeyInConfig)
1432{
1433 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1434 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1435
1436 int ret = test_retry(N_RETRIES, {.use_dynamic_tls_crypt = true});
1437 EXPECT_EQ(ret, 0);
1438}
1439
1440TEST_F(ProtoUnitTest, DynamicTlsCryptRekeysTlsCryptV2WithServerkeyId)
1441{
1442 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1443 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1444
1445 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key", .use_dynamic_tls_crypt = true});
1446 EXPECT_EQ(ret, 0);
1447}
1448
1449// The two above run tls-crypt-v2-only servers, where the config the key is picked from and
1450// the mode the session is in cannot disagree. A server holding a tls-auth key as well --
1451// what PG deploys -- is the case that can: reset_tls_wrap_mode() prefers TLS_AUTH, so such a
1452// session starts as tls-auth and only decapsulate() converts it once the client's WKc
1453// arrives. Picking the key to mix from the config then had the server mix tls_auth_key while
1454// its tls-crypt-v2 client mixed Kc; the handshake came up fine and the session died at the
1455// first rekey, hours in. Both server key modes, as above.
1456TEST_F(ProtoUnitTest, DynamicTlsCryptRekeysTlsCryptV2OnTlsAuthServerWithServerkeyInConfig)
1457{
1458 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1459 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1460
1461 int ret = test_retry(N_RETRIES,
1462 {.use_tls_auth_with_tls_crypt_v2 = true,
1463 .use_dynamic_tls_crypt = true});
1464 EXPECT_EQ(ret, 0);
1465}
1466
1467TEST_F(ProtoUnitTest, DynamicTlsCryptRekeysTlsCryptV2OnTlsAuthServerWithServerkeyId)
1468{
1469 if (!openvpn::SSLLib::SSLAPI::support_key_material_export())
1470 GTEST_SKIP_("our mbed TLS implementation does not support TLS EKM");
1471
1472 int ret = test_retry(N_RETRIES,
1473 {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key",
1474 .use_tls_auth_with_tls_crypt_v2 = true,
1475 .use_dynamic_tls_crypt = true});
1476 EXPECT_EQ(ret, 0);
1477}
1478
1479// Regression test: when the tls-crypt-v2 WKc is appended to the first
1480// ciphertext-bearing control packet (EARLY_NEG_FLAG_RESEND_WKC -> the client
1481// emits CONTROL_WKC_V1), the SSL ciphertext placed into that packet must be
1482// trimmed to leave room for the WKc, so the assembled datagram still fits the
1483// control-channel frame. Without the reservation fix the packet overflows the
1484// frame by ~wkc.size() bytes and gets dropped, stalling the handshake.
1485TEST_F(ProtoUnitTest, TlsCryptV2WkcRidesFirstControlPacket)
1486{
1487 int ret = test_retry(N_RETRIES, {.tls_crypt_v2_key_fn = "tls-crypt-v2-client-with-serverkey.key", .force_resend_wkc = true});
1488 EXPECT_EQ(ret, 0);
1489}
1490
1491// Degenerate variant of the above: the control-channel payload is smaller
1492// than the WKc itself (mssfix-ctrl may go as low as 256 while a WKc can be
1493// up to 1024 bytes). The WKc reservation must clamp instead of wrapping the
1494// unsigned subtraction -- a wrap disables the trim entirely and the WKc
1495// packet overflows the frame again. The WKc of the test key is 328 bytes;
1496// 278 puts the payload just below it.
1497TEST_F(ProtoUnitTest, TlsCryptV2WkcLargerThanControlPayload)
1498{
1499 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});
1500 EXPECT_EQ(ret, 0);
1501}
1502
1503// Every control packet, including the WKc-bearing one, must stay within the
1504// configured mssfix_ctrl limit after all tls wrappings have been applied.
1505// 420 leaves just enough room for the unsplittable WKc packet (~406 bytes
1506// worst case: tls-crypt header + full ACK block + the 328 byte WKc).
1507TEST_F(ProtoUnitTest, TlsCryptV2ControlPacketCapHonored)
1508{
1509 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});
1510 EXPECT_EQ(ret, 0);
1511}
1512
1513// Security regression test: unwrap_tls_crypt_wkc() reads the 16-bit WKc length
1514// (wkc_len) from the last two bytes of the received packet. For CONTROL_WKC_V1
1515// packets that value is fully attacker-controlled and, before the bounds-check
1516// fix, was fed straight into unsigned pointer arithmetic
1517// (wkc_raw = orig_data + orig_size - wkc_len). A wkc_len larger than the packet
1518// underflowed the size_t computation into a wild pointer and a bogus/oversized
1519// ciphertext length, producing an out-of-bounds read during decryption -- a
1520// pre-authentication remote crash (DoS). The unwrap must instead reject the
1521// packet with Error::CC_ERROR without dereferencing out of bounds.
1522//
1523// Builds a minimal ProtoConfig / tls-crypt server context (no full handshake
1524// needed) since the malformed length is rejected before any key material is
1525// touched.
1526class TlsCryptV2WkcUnwrapTest : public testing::Test
1527{
1528 protected:
1531
1532 void SetUp() override
1533 {
1535 pcfg->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
1536 pcfg->set_tls_crypt_algs();
1537 // Fully initialize the server context (single server key, no key ID) so
1538 // that a malformed packet which slips past the length validation reaches
1539 // the real decrypt() read -- that is the read that goes out of bounds
1540 // without the fix (a segfault / ASan SEGV), and which the fix must avoid
1541 // by rejecting the packet up front.
1542 pcfg->tls_crypt_key.parse(read_text(TEST_KEYCERT_DIR "tls-auth.key"));
1543 tls_crypt_server = pcfg->tls_crypt_context->new_obj_recv();
1544 tls_crypt_server->init(nullptr,
1545 pcfg->tls_crypt_key.slice(OpenVPNStaticKey::HMAC),
1546 pcfg->tls_crypt_key.slice(OpenVPNStaticKey::CIPHER));
1547 }
1548
1549 // Build a CONTROL_WKC_V1 packet of the given size with the trailing 16-bit
1550 // WKc length field set to wkc_len (host order). Contents are otherwise
1551 // arbitrary -- the unwrap should bail on the length alone.
1552 BufferAllocated make_wkc_v1_packet(size_t size, uint16_t wkc_len)
1553 {
1555 buf.set_size(size);
1556 // op byte = op_compose(CONTROL_WKC_V1, key_id=0). CONTROL_WKC_V1 (11)
1557 // and op_compose() are protected members of ProtoContext, so encode it
1558 // directly here: (opcode << OPCODE_SHIFT[=3]) | key_id. Any opcode other
1559 // than CONTROL_HARD_RESET_CLIENT_V3 (10) selects the attacker-controlled
1560 // wkc_len branch being exercised.
1561 buf.data()[0] = static_cast<unsigned char>(11u << 3);
1562 const uint16_t net_wkc_len = htons(wkc_len);
1563 std::memcpy(buf.data() + size - sizeof(net_wkc_len), &net_wkc_len, sizeof(net_wkc_len));
1564 return buf;
1565 }
1566
1568 size_t frame_size() const
1569 {
1571 }
1572
1575 uint16_t min_wkc_len() const
1576 {
1577 return static_cast<uint16_t>(ProtoContext::KeyContext::wkc_overhead(*pcfg)
1579 }
1580};
1581
1582// wkc_len far larger than the packet: pre-fix this underflowed wkc_raw into a
1583// wild pointer read.
1584TEST_F(TlsCryptV2WkcUnwrapTest, RejectsWkcLenLargerThanPacket)
1585{
1586 BufferAllocated buf = make_wkc_v1_packet(200, 60000);
1588 EXPECT_EQ(ProtoContext::KeyContext::unwrap_tls_crypt_wkc(buf, *pcfg, *tls_crypt_server, unwrapped),
1590 EXPECT_FALSE(unwrapped.client_key.defined());
1591}
1592
1593// wkc_len smaller than the auth tag: pre-fix the decrypt ciphertext length
1594// (wkc_raw_size - hmac_size) underflowed to a huge oversized read.
1595TEST_F(TlsCryptV2WkcUnwrapTest, RejectsWkcLenSmallerThanAuthTag)
1596{
1597 BufferAllocated buf = make_wkc_v1_packet(200, 4);
1599 EXPECT_EQ(ProtoContext::KeyContext::unwrap_tls_crypt_wkc(buf, *pcfg, *tls_crypt_server, unwrapped),
1601 EXPECT_FALSE(unwrapped.client_key.defined());
1602}
1603
1604// strip_resent_wkc() takes the WKc off a retransmitted CONTROL_WKC_V1 without
1605// unwrapping it again. It reads the same attacker-controlled trailing length
1606// field as the unwrap above and needs the same guards, so exercise them here
1607// too: a length that survives validation is used to trim the packet, and one
1608// that doesn't must leave the packet alone and drop it.
1609
1610// A WKc's K_id names a file and the K_id is whatever the packet says it is, so a client whose
1611// key we never had -- or a forgery -- points at a file that is not there. read_text() throws
1612// open_file_error for it, which is not a BufferException, so it sailed past the only catch in
1613// decapsulate() and out of the psid cookie layer's intercept(), from a path reached before
1614// anything about the packet has been authenticated.
1615TEST_F(TlsCryptV2WkcUnwrapTest, UnknownServerKeyIdIsAnErrorAndNotAnException)
1616{
1617 pcfg->tls_crypt_v2_serverkey_id = true;
1618 pcfg->tls_crypt_v2_serverkey_dir = TEST_KEYCERT_DIR;
1619
1620 // room for a WKc behind a tls-crypt frame; the buffer is zero filled, so the K_id it
1621 // carries is 0 and names <dir>/00/00000000.key
1622 const uint16_t wkc_len = min_wkc_len();
1623 BufferAllocated buf = make_wkc_v1_packet(frame_size() + wkc_len, wkc_len);
1624
1627 EXPECT_NO_THROW(
1628 ret = ProtoContext::KeyContext::unwrap_tls_crypt_wkc(buf, *pcfg, *tls_crypt_server, unwrapped));
1629 EXPECT_EQ(ret, Error::DECRYPT_ERROR);
1630 EXPECT_FALSE(unwrapped.client_key.defined());
1631}
1632
1634{
1635 BufferAllocated buf = make_wkc_v1_packet(frame_size() + 300, 300);
1636 EXPECT_TRUE(ProtoContext::KeyContext::strip_resent_wkc(buf, *pcfg));
1637 // what is left is the frame the tls-crypt auth tag actually covers
1638 EXPECT_EQ(buf.size(), frame_size());
1639}
1640
1641TEST_F(TlsCryptV2WkcUnwrapTest, StripRejectsWkcLenLargerThanPacket)
1642{
1643 BufferAllocated buf = make_wkc_v1_packet(400, 60000);
1644 EXPECT_FALSE(ProtoContext::KeyContext::strip_resent_wkc(buf, *pcfg));
1645 EXPECT_EQ(buf.size(), 400u);
1646}
1647
1648// a WKc too small to even hold the client key it is supposed to wrap
1649TEST_F(TlsCryptV2WkcUnwrapTest, StripRejectsWkcLenSmallerThanClientKey)
1650{
1651 BufferAllocated buf = make_wkc_v1_packet(400, min_wkc_len() - 1);
1652 EXPECT_FALSE(ProtoContext::KeyContext::strip_resent_wkc(buf, *pcfg));
1653 EXPECT_EQ(buf.size(), 400u);
1654}
1655
1656// one byte more than the packet can spare: trimming it would leave less than a
1657// tls-crypt frame in front of the WKc
1658TEST_F(TlsCryptV2WkcUnwrapTest, StripRejectsWkcLeavingNoTlsCryptFrame)
1659{
1660 BufferAllocated buf = make_wkc_v1_packet(400, static_cast<uint16_t>(400 - frame_size() + 1));
1661 EXPECT_FALSE(ProtoContext::KeyContext::strip_resent_wkc(buf, *pcfg));
1662 EXPECT_EQ(buf.size(), 400u);
1663}
1664
1665// too short to hold a frame plus the trailing length field at all; the length
1666// read itself must not happen
1667TEST_F(TlsCryptV2WkcUnwrapTest, StripRejectsPacketShorterThanAFrame)
1668{
1669 BufferAllocated buf = make_wkc_v1_packet(frame_size() + 1, 300);
1670 EXPECT_FALSE(ProtoContext::KeyContext::strip_resent_wkc(buf, *pcfg));
1671}
1672
1673// with server key IDs in use -- how PG deploys tls-crypt-v2 -- the WKc carries a
1674// 4 byte K_id as well, so the minimum grows by that much
1675TEST_F(TlsCryptV2WkcUnwrapTest, StripAccountsForServerKeyId)
1676{
1677 pcfg->tls_crypt_v2_serverkey_id = true;
1678 // the one place the number is spelled out rather than asked for: length field, a
1679 // SHA-256 tag, K_id and the client key
1680 ASSERT_EQ(min_wkc_len(), sizeof(uint16_t) + 32 + sizeof(uint32_t) + OpenVPNStaticKey::KEY_SIZE);
1681
1682 BufferAllocated too_small = make_wkc_v1_packet(400, min_wkc_len() - 1);
1683 EXPECT_FALSE(ProtoContext::KeyContext::strip_resent_wkc(too_small, *pcfg));
1684
1685 BufferAllocated ok = make_wkc_v1_packet(400, min_wkc_len());
1686 EXPECT_TRUE(ProtoContext::KeyContext::strip_resent_wkc(ok, *pcfg));
1687 EXPECT_EQ(ok.size(), 400u - min_wkc_len());
1688}
1689#endif
1690
1691TEST_F(ProtoUnitTest, BaseMultipleThread)
1692{
1693 unsigned int num_threads = std::thread::hardware_concurrency();
1694#if defined(PROTO_N_THREADS) && PROTO_N_THREADS >= 1
1695 num_threads = PROTO_N_THREADS;
1696#endif
1697
1698 std::vector<std::thread> running_threads{};
1699 std::vector<int> results(num_threads, -777);
1700
1701 for (unsigned int i = 0; i < num_threads; ++i)
1702 {
1703 running_threads.emplace_back([i, &results]()
1704 {
1705 /* Use ekm on odd threads */
1706 const bool use_ekm = openvpn::SSLLib::SSLAPI::support_key_material_export() && (i % 2 == 0);
1707 results[i] = test_retry(N_RETRIES, { .use_tls_ekm = use_ekm }); });
1708 }
1709 for (unsigned int i = 0; i < num_threads; ++i)
1710 {
1711 running_threads[i].join();
1712 }
1713
1714
1715 // expect 1 for all threads
1716 const std::vector<int> expected_results(num_threads, 0);
1717
1718 EXPECT_THAT(expected_results, ::testing::ContainerEq(results));
1719}
1720
1721TEST(Proto, IvCiphersAead)
1722{
1723 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, true, false);
1724
1725 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1726
1727 auto infostring = protoConf.peer_info_string(false);
1728
1729 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1730 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1731
1732
1733 std::string expectedstr{"IV_CIPHERS=AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1734 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1735 expectedstr += ":CHACHA20-POLY1305";
1736
1737 EXPECT_EQ(ivciphers, expectedstr);
1738}
1739
1740TEST(Proto, IvCiphersNonPreferred)
1741{
1742 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(nullptr, false, false);
1743
1744 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1745
1746 auto infostring = protoConf.peer_info_string(true);
1747
1748 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1749 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1750
1751
1752 std::string expectedstr{"IV_CIPHERS=AES-128-CBC:AES-192-CBC:AES-256-CBC:AES-128-GCM:AES-192-GCM:AES-256-GCM"};
1753 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1754 expectedstr += ":CHACHA20-POLY1305";
1755
1756 EXPECT_EQ(ivciphers, expectedstr);
1757}
1758
1759TEST(Proto, IvCiphersLegacy)
1760{
1761
1762 /* Need to a whole lot of things to enable legacy provider/OpenSSL context */
1763 SSLLib::SSLAPI::Config::Ptr config = new SSLLib::SSLAPI::Config;
1764 EXPECT_TRUE(config);
1765
1766 StrongRandomAPI::Ptr rng(new SSLLib::RandomAPI());
1767 config->set_rng(rng);
1768
1769 config->set_mode(Mode(Mode::CLIENT));
1771 config->set_local_cert_enabled(false);
1772 config->enable_legacy_algorithms(true);
1773
1774 auto factory_client = config->new_factory();
1775 EXPECT_TRUE(factory_client);
1776
1777 auto client = factory_client->ssl();
1778 auto libctx = factory_client->libctx();
1779
1780
1781 CryptoAlgs::allow_default_dc_algs<SSLLib::CryptoAPI>(libctx, false, true);
1782
1783 auto protoConf = openvpn::ProtoContext::ProtoConfig();
1784
1785 auto infostring = protoConf.peer_info_string(false);
1786
1787 auto ivciphers = infostring.substr(infostring.find("IV_CIPHERS="));
1788 ivciphers = ivciphers.substr(0, ivciphers.find("\n"));
1789
1790
1791
1792 std::string expectedstr{"IV_CIPHERS=none:AES-128-CBC:AES-192-CBC:AES-256-CBC:DES-CBC:DES-EDE3-CBC"};
1793
1794 if (SSLLib::CryptoAPI::CipherContext::is_supported(libctx, openvpn::CryptoAlgs::BF_CBC))
1795 expectedstr += ":BF-CBC";
1796
1797 expectedstr += ":AES-128-GCM:AES-192-GCM:AES-256-GCM";
1798
1799 if (SSLLib::CryptoAPI::CipherContextAEAD::is_supported(nullptr, openvpn::CryptoAlgs::CHACHA20_POLY1305))
1800 expectedstr += ":CHACHA20-POLY1305";
1801
1802 EXPECT_EQ(ivciphers, expectedstr);
1803}
1804
1805TEST(Proto, ControlmessageInvalidchar)
1806{
1807 std::string valid_auth_fail{"AUTH_FAILED: go away"};
1808 std::string valid_auth_fail_newline_end{"AUTH_FAILED: go away\n"};
1809 std::string invalid_auth_fail{"AUTH_FAILED: go\n away\n"};
1810 std::string lot_of_whitespace{"AUTH_FAILED: a lot of white space\n\n\r\n\r\n\r\n"};
1811 std::string only_whitespace{"\n\n\r\n\r\n\r\n"};
1812 std::string empty{""};
1813
1814 BufferAllocated valid_auth_fail_buf{reinterpret_cast<const unsigned char *>(valid_auth_fail.c_str()), valid_auth_fail.size(), BufAllocFlags::GROW};
1815 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};
1816 BufferAllocated invalid_auth_fail_buf{reinterpret_cast<const unsigned char *>(invalid_auth_fail.c_str()), invalid_auth_fail.size(), BufAllocFlags::GROW};
1817 BufferAllocated lot_of_whitespace_buf{reinterpret_cast<const unsigned char *>(lot_of_whitespace.c_str()), lot_of_whitespace.size(), BufAllocFlags::GROW};
1818 BufferAllocated only_whitespace_buf{reinterpret_cast<const unsigned char *>(only_whitespace.c_str()), only_whitespace.size(), BufAllocFlags::GROW};
1819 BufferAllocated empty_buf{reinterpret_cast<const unsigned char *>(empty.c_str()), empty.size(), BufAllocFlags::GROW};
1820
1821 auto msg = ProtoContext::read_control_string<std::string>(valid_auth_fail_buf);
1822 EXPECT_EQ(msg, valid_auth_fail);
1824
1825 auto msg2 = ProtoContext::read_control_string<std::string>(valid_auth_fail_newline_end_buf);
1826 EXPECT_EQ(msg2, valid_auth_fail);
1828
1829 auto msg3 = ProtoContext::read_control_string<std::string>(invalid_auth_fail_buf);
1830 EXPECT_EQ(msg3, "AUTH_FAILED: go\n away");
1831 EXPECT_FALSE(Unicode::is_valid_utf8(msg3, Unicode::UTF8_NO_CTRL));
1832
1833 auto msg4 = ProtoContext::read_control_string<std::string>(lot_of_whitespace_buf);
1834 EXPECT_EQ(msg4, "AUTH_FAILED: a lot of white space");
1836
1837 auto msg5 = ProtoContext::read_control_string<std::string>(only_whitespace_buf);
1838 EXPECT_EQ(msg5, "");
1840
1841 auto msg6 = ProtoContext::read_control_string<std::string>(empty_buf);
1842 EXPECT_EQ(msg6, "");
1844}
1845
1852
1854{
1855 public:
1857 {
1858 events.push_back(event);
1859 }
1860
1861 std::vector<openvpn::ClientEvent::Base::Ptr> events;
1862};
1863
1864TEST(Proto, ClientProtoCheckCcMsg)
1865{
1866 asio::io_context io_context;
1867 ClientRandomAPI::Ptr rng_cli(new ClientRandomAPI());
1868 Frame::Ptr frame(new Frame(Frame::Context(128, 378, 128, 0, 16, BufAllocFlags::NO_FLAGS)));
1869 MySessionStats::Ptr cli_stats(new MySessionStats);
1870 Time time;
1871
1873 /* keep a reference to the right class to avoid repeated casted */
1874 EventQueueVector *eqv = dynamic_cast<EventQueueVector *>(eqv_ptr.get());
1875 /* check that the cast worked */
1876 ASSERT_TRUE(eqv);
1877
1878 MockCallback mockCB;
1881 frame,
1882 rng_cli,
1883 std::move(cli_stats),
1884 time);
1885 clisessconf.cli_events = std::move(eqv_ptr);
1886 openvpn::ClientProto::Session::Ptr clisession = new ClientProto::Session{io_context, clisessconf, &mockCB};
1887
1888 clisession->validate_and_post_cc_msg("valid message");
1889
1890
1891 EXPECT_TRUE(eqv->events.empty());
1892
1893 clisession->validate_and_post_cc_msg("invalid\nmessage");
1894 EXPECT_EQ(eqv->events.size(), 1);
1895 auto ev = eqv->events.back();
1896 auto uf = dynamic_cast<openvpn::ClientEvent::UnsupportedFeature *>(ev.get());
1897 /* check that the cast worked */
1898 ASSERT_TRUE(uf);
1899 EXPECT_EQ(uf->name, "Invalid chars in control message");
1900 EXPECT_EQ(uf->reason, "Control channel message with invalid characters not allowed to be send with post_cc_msg");
1901}
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_
size_t frame_size() const
Smallest tls-crypt frame a WKc can follow, from the code under test.
BufferAllocated make_wkc_v1_packet(size_t size, uint16_t wkc_len)
ProtoContext::ProtoConfig::Ptr pcfg
TLSCryptInstance::Ptr tls_crypt_server
uint16_t min_wkc_len() const
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:1448
bool empty() const
Returns true if the buffer is empty.
Definition buffer.hpp:1235
void set_size(const size_t size)
After an external method, operating on the array as a mutable unsigned char buffer,...
Definition buffer.hpp:1382
@ READ_BIO_MEMQ_STREAM
Definition frame.hpp:41
size_t prepare(const unsigned int context, Buffer &buf) const
Definition frame.hpp:263
static bool strip_resent_wkc(Buffer &recv, const ProtoConfig &proto_config)
Virtually remove a resent WKc from the end of a CONTROL_WKC_V1 packet.
Definition proto.hpp:3108
static size_t tls_crypt_frame_size(const ProtoConfig &proto_config)
Smallest tls-crypt frame a WKc can be appended to.
Definition proto.hpp:2834
static Error::Type unwrap_tls_crypt_wkc(Buffer &recv, const ProtoConfig &proto_config, TLSCryptInstance &tls_crypt_server, UnwrappedWkc &unwrapped)
Extract and process the TLS crypt WKc information.
Definition proto.hpp:2926
static size_t wkc_overhead(const ProtoConfig &proto_config)
What a WKc holds besides the client key and the metadata.
Definition proto.hpp:2850
bool control_net_recv(const PacketType &type, BufferPtr &&net_bp)
Definition proto.hpp:4967
const Time::Duration & slowest_handshake()
Definition proto.hpp:5073
const Time & now() const
Definition proto.hpp:5174
void flush(const bool control_channel)
Definition proto.hpp:4894
void control_send(BufferPtr &&app_bp)
Definition proto.hpp:4950
PacketType packet_type(const Buffer &buf)
Definition proto.hpp:4844
void data_encrypt(BufferAllocated &in_out)
Definition proto.hpp:4988
static unsigned char op_compose(const unsigned int opcode, const unsigned int key_id)
Definition proto.hpp:326
static void write_auth_string(const S &str, Buffer &buf)
Definition proto.hpp:1572
bool is_server() const
Definition proto.hpp:5198
bool data_decrypt(const PacketType &type, BufferAllocated &in_out)
Definition proto.hpp:4998
Error::Type invalidation_reason() const
Definition proto.hpp:5085
unsigned int negotiations() const
Definition proto.hpp:5067
Time next_housekeeping() const
Definition proto.hpp:4932
bool invalidated() const
Definition proto.hpp:5079
void reset(const ProtoSessionID cookie_psid=ProtoSessionID())
Resets ProtoContext *this to it's initial state.
Definition proto.hpp:4733
void start(const ProtoSessionID cookie_psid=ProtoSessionID())
Initialize the state machine and start protocol negotiation.
Definition proto.hpp:4857
const ProtoConfig & conf() const
Definition proto.hpp:5218
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
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
virtual void init(SSLLib::Ctx libctx, const StaticKey &key_hmac, const StaticKey &key_crypt)=0
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 CONSTRUCT_ZERO(1U<< 0)
if enabled, constructors/init will zero allocated space
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:1899
ProtoContext::ProtoConfig::Ptr proto_context_config
Definition cliproto.hpp:126
unsigned int mssfix
Definition mssparms.hpp:71
What a WKc yields, owned by whoever asked for the unwrap.
Definition proto.hpp:2911
OpenVPNStaticKey client_key
Kc, the client key the WKc wrapped.
Definition proto.hpp:2913
const std::string & tls_crypt_v2_key_fn
bool client_tls_auth_only
bool tls_version_mismatch
bool force_resend_wkc
bool use_tls_auth_with_tls_crypt_v2
size_t mssfix_ctrl
size_t control_payload
bool use_dynamic_tls_crypt
bool spoof_hard_reset_v3
static const char config[]
#define TLS_TIMEOUT_CLIENT
#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="", bool tls_auth_only=false, bool use_dynamic_tls_crypt=false)
int test_retry(const int n_retries, const struct proto_test &test_config)
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,...)