OpenVPN
test_acc.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2025 OpenVPN Inc <sales@openvpn.net>
9 * Copyright (C) 2025 Arne Schwabe <arne@rfc2549.org>
10 *
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2
14 * as published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26#ifdef HAVE_CONFIG_H
27#include "config.h"
28#endif
29
30#include "syshead.h"
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdarg.h>
35#include <string.h>
36#include <setjmp.h>
37#include <cmocka.h>
38
39#include "acc.h"
40#include "test_acc.h"
41#include "test_common.h"
42
43#include "mock_msg.h"
44#include "multi.h"
45
47
48/* Mock functions */
49bool
51 const char *str, unsigned int msglevel)
52{
53 assert_int_in_range(strlen(str), 0, 2047);
54
56 return true;
57}
58
59void
63
64void
65auth_set_client_reason(struct tls_multi *multi, const char *reason)
66{
67}
68
69#define MSG_PAYLOAD "FgMBARkBAAEVAwNanUalkEDDxLBpZw9JnjI3tBM" \
70 "r4engpg/cDgS48DMaxyCdbzofNjQJU9Y0DD66z/notFT0cF1d60nTS" \
71 "4md4OJwoQAwEwITAxMBwCzAMACfzKnMqMyqwCvALwCewCTAKABrwCP" \
72 "AJwBnwArAFAA5wAnAEwAzAQAAnP8BAAEAAAsABAMAAQIACgAWABQAH" \
73 "QAXAB4AGQAYAQABAQECAQMBBAAWAAAAFwAAAA0AMAAuBAMFAwYDCAc" \
74 "ICAgaCBsIHAgJCAoICwgECAUIBgQBBQEGAQMDAwEDAgQCBQIGAgArA" \
75 "AUEAwQDAwAtAAIBAQAzACYAJAAdACCk4Tz2PB/2FsxOfOIV4gn/NyJ" \
76 "93rQwityP9eKSijXgcQ=="
77
78void
80{
81#ifndef ENABLE_MANAGEMENT
82 skip();
83#else
84 /* ensure that the messages get to mock_msg */
85 x_debug_level = 3;
86 management = (void *)0x12345678;
87 struct gc_arena gc = gc_new();
88
89 /* contains a TLS 1.3 ClientHello */
90 const char msg[] = "ACC,cck1,384,6," MSG_PAYLOAD;
91
92 struct buffer msg_buf;
93 struct context c = { 0 };
95
97
100 buf_set_read(&msg_buf, (void *)msg, sizeof(msg));
101
102 receive_acc_message(&c, &msg_buf);
103 assert_string_equal(mock_msg_buf, "WARNING: Received malformed custom app control channel message (ACC not enabled or no negotiated protocols): 4143432c 63636b31 2c333834 2c362c46 674d4241 526b4241 41455641 774e616[more...]");
104 assert_string_equal(mock_managment_buf, "");
105
106 c.c2.tls_multi->acc_negotiated_protocols = "no:common:protocol";
107 receive_acc_message(&c, &msg_buf);
108 assert_string_equal(mock_msg_buf, "WARNING: Received malformed custom app control channel message (protocol 'cck1' not in list of negotiated protocols 'no:common:protocol'): 4143432c 63636b31 2c333834 2c362c46 674d4241 526b4241 41455641 774e616[more...]");
109 assert_string_equal(mock_managment_buf, "");
110
111 c.c2.tls_multi->acc_negotiated_protocols = "cck1:flower:power:fortune";
112 receive_acc_message(&c, &msg_buf);
113
114 assert_string_equal(mock_msg_buf, "Received custom app control message (protocol 'cck1')");
115 assert_string_equal(mock_managment_buf, ">CLIENT:ACC,0,0,cck1,0," MSG_PAYLOAD);
116
117 const char flower_msg[] = "ACC,flower,48,6,SSBhbSAAIEtlcm1pdCD//SB0aGUg77+94oCPZnJvZyEAAA==";
118 buf_set_read(&msg_buf, (void *)flower_msg, sizeof(flower_msg));
119 receive_acc_message(&c, &msg_buf);
120 assert_string_equal(mock_msg_buf, "Received custom app control message (protocol 'flower')");
121 assert_string_equal(mock_managment_buf, ">CLIENT:ACC,0,0,flower,0,SSBhbSAAIEtlcm1pdCD//SB0aGUg77+94oCPZnJvZyEAAA==");
122
124 const char msg_incorrect_len[] = "ACC,fortune,62,6,InsgIm1lIjogImZyb2ciLCAAeGZm/SJtc2ciOiAiSSBhbSAAS2VybWl0IiB9Ig==";
125 buf_set_read(&msg_buf, (void *)msg_incorrect_len, sizeof(msg_incorrect_len));
126 receive_acc_message(&c, &msg_buf);
127 const char *error = "WARNING: Received malformed custom app control channel "
128 "message (field length 62, payload length 64 mismatch): "
129 "4143432c 666f7274 756e652c 36322c36 2c496e73 67496d31 "
130 "6c496a6f 67496d5[more...]";
131
132 assert_string_equal(mock_msg_buf, error);
133 assert_string_equal(mock_managment_buf, "");
134
136 const char msg_fragment[] = "ACC,power,12,6F,aGVsbG8gdw==";
137 buf_set_read(&msg_buf, (void *)msg_fragment, sizeof(msg_fragment));
138 receive_acc_message(&c, &msg_buf);
139 assert_string_equal(mock_msg_buf, "Received custom app control message (protocol 'power', fragment)");
140 assert_string_equal(mock_managment_buf, ">CLIENT:ACC,0,0,power,1,aGVsbG8gdw==");
141
143 /* check two encoding present */
144 const char flower_msg_two_encs[] = "ACC,flower,48,6A,SSBhbSAAIEtlcm1pdCD//SB0aGUg77+94oCPZnJvZyEAAA==";
145 buf_set_read(&msg_buf, (void *)flower_msg_two_encs, sizeof(flower_msg_two_encs));
146 receive_acc_message(&c, &msg_buf);
147
148 error = "WARNING: Received malformed custom app control channel message "
149 "(number of encodings must be exactly one (B64=1, ASCII=1)): "
150 "4143432c 666c6f77 65722c34 382c3641 2c535342 68625341 41494574 "
151 "6c636d3[more...]";
152
153 assert_string_equal(mock_msg_buf, error);
154 assert_string_equal(mock_managment_buf, "");
155
156 /* no encoding present */
157 const char flower_msg_no_encs[] = "ACC,flower,48,,SSBhbSAAIEtlcm1pdCD//SB0aGUg77+94oCPZnJvZyEAAA==";
158 buf_set_read(&msg_buf, (void *)flower_msg_no_encs, sizeof(flower_msg_no_encs));
159 receive_acc_message(&c, &msg_buf);
160
161 error = "WARNING: Received malformed custom app control channel message "
162 "(number of encodings must be exactly one (B64=0, ASCII=0)): "
163 "4143432c 666c6f77 65722c34 382c2c53 53426862 53414149 45746c63 "
164 "6d31706[more...]";
165 assert_string_equal(mock_msg_buf, error);
166 assert_string_equal(mock_managment_buf, "");
167
168 x_debug_level = 0;
169 management = NULL;
170 gc_free(&gc);
171#endif
172}
173
174void
176{
177 struct gc_arena gc = gc_new();
178 /* parameters to INFO message */
179 const char *info_acc_msg = "4096 A:6 flower:happy";
180
181 int max_len = 0;
182 const char *protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, true, &gc);
183 assert_string_equal(protocols, "flower:happy");
184 assert_int_equal(max_len, 1280);
185
186 /* a client does not accept a length longer than it supports */
187 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, false, &gc);
188 assert_null(protocols);
189
190 /* message with lower limit than our, should work for client and server */
191 info_acc_msg = "1111 A:6 flower:happy";
192 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, false, &gc);
193 assert_string_equal(protocols, "flower:happy");
194 assert_int_equal(max_len, 1111);
195
196 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, true, &gc);
197 assert_string_equal(protocols, "flower:happy");
198 assert_int_equal(max_len, 1111);
199
200 /* more encodings than supported. Server should be okay, client should fail */
201 info_acc_msg = "1200 A:6:B flower:happy";
202 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, false, &gc);
203 assert_null(protocols);
204
205 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, true, &gc);
206 assert_string_equal(protocols, "flower:happy");
207 assert_int_equal(max_len, 1200);
208
209 /* extra parameter */
210 info_acc_msg = "1400 A:6 flower:happy 77";
211 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, true, &gc);
212 assert_null(protocols);
213
214 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, false, &gc);
215 assert_null(protocols);
216
217
218 const char *iv_acc_capabilities = "1400,A:6,flower:happy:power";
219 protocols = parse_acc_parameters(iv_acc_capabilities, ",", &max_len, true, &gc);
220 assert_string_equal(protocols, "flower:happy:power");
221
222 /* too small protocol length */
223 info_acc_msg = "32 A:6 flower:happy";
224 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, true, &gc);
225 assert_null(protocols);
226
227 /* non-numerical protocol length */
228 info_acc_msg = "abff A:6 flower:happy";
229 protocols = parse_acc_parameters(info_acc_msg, " ", &max_len, true, &gc);
230 assert_null(protocols);
231
232 gc_free(&gc);
233}
234
235void
237{
238 struct multi_instance mi = { 0 };
239 struct context *c = &mi.context;
240 c->options.gc = gc_new();
241
243
244 c->c2.tls_multi->peer_info = "IV_PROTO=4321\nIV_ACC=1400,A:6,flower:happy:power";
245 c->options.acc_protocols = "power:flower:star";
246 struct tls_multi *multi = c->c2.tls_multi;
248 multi->session[TM_ACTIVE].opt = &multi->opt;
249 multi->opt.es = env_set_create(&c->options.gc);
250
252
253 assert_int_equal(multi->acc_max_message_length, ACC_MAX_MSG_LEN);
254 assert_string_equal(multi->acc_negotiated_protocols, "power:flower");
255
256 assert_string_equal(env_set_get(multi->opt.es, "acc_protocols"), "acc_protocols=power:flower");
257 assert_string_equal(env_set_get(multi->opt.es, "acc_message_len"), "acc_message_len=1280");
258
259 free(multi->acc_negotiated_protocols);
260 gc_free(&c->options.gc);
261}
262
263void
265{
266 struct multi_instance mi = { 0 };
267 struct context *c = &mi.context;
268 c->options.gc = gc_new();
269
271 bool ret;
272 struct tls_multi *multi = c->c2.tls_multi;
273 c->options.acc_protocols = "power:flower:emergency";
275 multi->session[TM_ACTIVE].opt = &multi->opt;
276 multi->opt.es = env_set_create(&c->options.gc);
277
278 c->c2.tls_multi->peer_info = "IV_PROTO=4321\nIV_ACC=1400,A:6,flower:emergency:power";
280
282
283 ret = send_acc_message(c, c->c2.tls_multi, session, "emergency", true,
284 "EMERGENCY BROADCAST MESSAGE - THIS IS NOT A DRILL:", false);
285
286 assert_true(ret);
287 assert_string_equal(control_channel_message_sent,
288 "ACC,emergency,50,AF,EMERGENCY BROADCAST MESSAGE - THIS IS NOT A DRILL:");
289
290 ret = send_acc_message(c, c->c2.tls_multi, session, "emergency", false,
291 "THE GOVERNMENT HAS ISSUED A RAINBOW COLOURED ALERT FOR YOUR AREA.", false);
292 assert_true(ret);
293 assert_string_equal(control_channel_message_sent,
294 "ACC,emergency,65,A,THE GOVERNMENT HAS ISSUED A RAINBOW COLOURED ALERT FOR YOUR AREA.");
295
296
297 /* test a long message (> 1000) with fragment to get the maximum header size */
298 char long_message[1200] = { 0 };
299
300 for (int i = 0; i < 1024; i++)
301 {
302 long_message[i] = (char)(' ' + (i % 95));
303 }
304
305 /* last char of the message is a i and then a \0 */
306 assert_int_equal(long_message[1023], 'i');
307 assert_int_equal(long_message[1024], '\0');
308
309 ret = send_acc_message(c, c->c2.tls_multi, session, "emergency", true,
310 long_message, false);
311
312 assert_true(ret);
313 size_t cc_len = strlen(control_channel_message_sent);
314 assert_int_equal(control_channel_message_sent[cc_len - 1], 'i');
315 const char *expected_start_cc = "ACC,emergency,1024,AF, !\"#$%&'()*+,-./012345";
316 assert_memory_equal(control_channel_message_sent, expected_start_cc, strlen(expected_start_cc));
317
318 free(multi->acc_negotiated_protocols);
319 gc_free(&c->options.gc);
320}
321
322void
324{
325 const char *empty = "";
326 const char *protos = "power:flower:emergency";
327
328 struct gc_arena gc = gc_new();
329
330 struct buffer t1 = get_list_intersection(&gc, empty, protos);
331 assert_int_equal(buf_len(&t1), 0);
332
333 struct buffer t2 = get_list_intersection(&gc, protos, empty);
334 assert_int_equal(buf_len(&t2), 0);
335
336 struct buffer t3 = get_list_intersection(&gc, protos, protos);
337 assert_string_equal(buf_cstr(&t3), protos);
338
339 const char *protos2 = "flower:emergency:power:mario";
340 struct buffer t4 = get_list_intersection(&gc, protos2, protos);
341 assert_string_equal(buf_cstr(&t4), "flower:emergency:power");
342
343 const char *protos3 = "super:paper:mario:flower";
344 struct buffer t5 = get_list_intersection(&gc, protos2, protos3);
345 assert_string_equal(buf_cstr(&t5), "flower:mario");
346
347 const char *proto4 = "flower:flower:flower:flower";
348 struct buffer t6 = get_list_intersection(&gc, proto4, "flower");
349 assert_string_equal(buf_cstr(&t6), "flower");
350
351
352 gc_free(&gc);
353}
bool send_acc_message(struct context *c, struct tls_multi *multi, struct tls_session *session, const char *protocol, bool fragment, const char *acc_msg_payload, bool base64)
Definition acc.c:240
void receive_acc_message(struct context *c, const struct buffer *buffer)
This method parses an app custom control message and delivers it to the management interface.
Definition acc.c:152
char * parse_acc_parameters(const char *capabilities, const char *delim, int *max_acc_len, bool server, struct gc_arena *gc)
Parses an info message from the server that contains app custom control info information prior to the...
Definition acc.c:287
void determine_common_acc_protocols(struct tls_multi *multi, struct tls_session *session)
Parses the IV_ACC of the peer and sets multi.acc_negotiated_protocols to the common protocols of serv...
Definition acc.c:382
struct buffer get_list_intersection(struct gc_arena *gc, const char *list1, const char *list2)
Calculates the intersection of two list that are both separated by : Items in the result will have th...
Definition acc.c:351
#define ACC_MAX_MSG_LEN
Definition acc.h:32
static const char * buf_cstr(const struct buffer *buf)
Return the buffer content pointer cast to const char *.
Definition buffer.h:585
static int buf_len(const struct buffer *buf)
Return the length of the buffer content.
Definition buffer.h:462
static void buf_set_read(struct buffer *buf, const uint8_t *data, size_t size)
Initialise a buffer with an externally provided read-only memory region.
Definition buffer.h:687
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Allocate and zero-initialise a garbage-collected object of the given type.
Definition buffer.h:2123
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
Definition buffer.h:1965
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
Definition buffer.h:1949
const char * env_set_get(const struct env_set *es, const char *name)
Definition env_set.c:200
struct env_set * env_set_create(struct gc_arena *gc)
Definition env_set.c:155
#define TM_ACTIVE
Active tls_session.
Definition ssl_common.h:552
char mock_managment_buf[MOCK_MSG_BUF]
Definition mock_msg.c:46
char mock_msg_buf[MOCK_MSG_BUF]
Definition mock_msg.c:45
Header file for server-mode related structures and functions.
#define CLEAR(x)
Definition basic.h:32
msglvl_t x_debug_level
Definition error.c:48
#define msg(flags,...)
Definition error.h:152
#define MODE_SERVER
Definition options.h:265
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
struct man_def_auth_context mda_context
Definition openvpn.h:450
struct tls_multi * tls_multi
TLS state structure for this VPN tunnel.
Definition openvpn.h:324
Contains all state information for one tunnel.
Definition openvpn.h:471
struct context_2 c2
Level 2 context.
Definition openvpn.h:516
struct options options
Options loaded from command line or configuration file.
Definition openvpn.h:472
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
Server-mode state structure for one single VPN tunnel.
Definition multi.h:102
struct context context
The context structure storing state for this VPN tunnel.
Definition multi.h:150
const char * acc_protocols
The app custom control protocols we should announce as supported.
Definition options.h:717
int mode
Definition options.h:266
struct gc_arena gc
Definition options.h:258
Security parameter state for a single VPN tunnel.
Definition ssl_common.h:619
char * peer_info
A multi-line string of general-purpose info received from peer over control channel.
Definition ssl_common.h:680
int acc_max_message_length
the maximum length of an ACC control channel message
Definition ssl_common.h:741
struct tls_options opt
Definition ssl_common.h:624
struct tls_session session[TM_SIZE]
Array of tls_session objects representing control channel sessions with the remote peer.
Definition ssl_common.h:721
char * acc_negotiated_protocols
the protocols that are negotiated with the peer.
Definition ssl_common.h:738
struct env_set * es
Definition ssl_common.h:418
const char * acc_protocols
The app custom control protocols we should announce as supported.
Definition ssl_common.h:462
struct man_def_auth_context * mda_context
Definition ssl_common.h:442
Security parameter state of a single session within a VPN tunnel.
Definition ssl_common.h:497
struct tls_options * opt
Definition ssl_common.h:499
#define MSG_PAYLOAD
Definition test_acc.c:69
void test_acc_parse_client_messages(void **state)
Definition test_acc.c:79
void auth_set_client_reason(struct tls_multi *multi, const char *reason)
Sets the reason why authentication of a client failed.
Definition test_acc.c:65
void test_acc_send_message(void **state)
Definition test_acc.c:264
void test_acc_common_protocols(void **state)
Definition test_acc.c:236
void test_list_intersection(void **state)
Definition test_acc.c:323
bool send_control_channel_string_dowork(struct tls_session *session, const char *str, unsigned int msglevel)
Definition test_acc.c:50
char control_channel_message_sent[2048]
Definition test_acc.c:46
void test_parse_acc_parameters(void **state)
Definition test_acc.c:175
void send_push_reply_auth_token(struct tls_multi *multi)
Sends a push reply message only containin the auth-token to update the auth-token on the client.
Definition test_acc.c:60
#define assert_int_in_range(value, min, max)
Definition test_common.h:51
struct gc_arena gc
Definition test_ssl.c:138