OpenVPN
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 <string.h>
33#include "buffer.h"
34#include "error.h"
35#include "acc.h"
36#include "forward.h"
37#include "options_util.h"
38#include "ssl_util.h"
39#include "ssl_ncp.h"
40#include "multi.h"
41
42static void
43log_acc_message(struct context *c, const struct buffer *buf, int payload_len,
44 const char *protocol, int flags)
45{
47#ifdef ENABLE_MANAGEMENT
48 struct gc_arena gc = gc_new();
49 const char *payload_msg = NULL;
50
51 /* For simplicity, we always encode payload to be base64 encoded
52 * if not already in base64 format */
53 if (flags & ACC_MESSAGE_FLAGS_ASCII)
54 {
55 char *b64out = NULL;
56 ASSERT(openvpn_base64_encode(CBPTR(buf), payload_len, &b64out) >= 0);
57 gc_addspecial(b64out, free, &gc);
58 payload_msg = b64out;
59 }
60 else
61 {
62 payload_msg = CBSTR(buf);
63 }
64
65 if (management)
66 {
68
69 if (c->options.mode == MODE_SERVER)
70 {
71 /* server mode. Report client context */
72 struct man_def_auth_context *mda = session->opt->mda_context;
73 unsigned int mda_key_id = get_primary_key(c->c2.tls_multi)->mda_key_id;
74 msg(M_CLIENT, ">CLIENT:ACC,%lu,%u,%s,%d,%s",
75 mda->cid, mda_key_id, protocol, fragment, payload_msg);
76 }
77 else
78 {
79 /* Client mode. Do not a report a CLIENT id */
80 msg(M_CLIENT, ">ACC:%s,%d,%s", protocol, fragment, payload_msg);
81 }
82 }
83 gc_free(&gc);
84#endif /* ifdef ENABLE_MANAGEMENT */
85 msg(D_PUSH, "Received custom app control message (protocol '%s'%s)",
86 protocol, fragment ? ", fragment" : "");
87}
88
89
90int
91parse_acc_message_flags(const char *flags, const char **err_reason, struct gc_arena *gc)
92{
93 int acc_flags = 0;
94
95 for (const char *flag = flags; *flag != '\0'; flag++)
96 {
97 if (*flag == 'A')
98 {
99 acc_flags |= ACC_MESSAGE_FLAGS_ASCII;
100 }
101 else if (*flag == '6')
102 {
103 acc_flags |= ACC_MESSAGE_FLAGS_BASE64;
104 }
105 else if (*flag == 'F')
106 {
107 acc_flags |= ACC_MESSAGE_FLAGS_FRAGMENT;
108 }
109 else
110 {
111 *err_reason = "Unknown flag in flags";
112 return -1;
113 }
114 }
115 /* The message should be encoded with exactly one encoding. Ensure that
116 * only one of the flags is present */
117 bool asciienc = (bool)(acc_flags & ACC_MESSAGE_FLAGS_ASCII);
118 bool base64enc = (bool)(acc_flags & ACC_MESSAGE_FLAGS_BASE64);
119
120 if (base64enc + asciienc != 1)
121 {
122 char *tmp = gc_malloc(512, 1, gc);
123 snprintf(tmp, 512, "number of encodings must be exactly one "
124 "(B64=%d, ASCII=%d)",
125 base64enc, asciienc);
126 *err_reason = tmp;
127 return -1;
128 }
129
130 return acc_flags;
131}
132
138static int
139parse_acc_message_flags_buf(struct buffer *buf, const char **err_reason, struct gc_arena *gc)
140{
141 const char *flags = buf_extract_field(buf, ',', gc);
142
143 if (!flags)
144 {
145 *err_reason = "could not extract flags field";
146 return -1;
147 }
148 return parse_acc_message_flags(flags, err_reason, gc);
149}
150
151void
152receive_acc_message(struct context *c, const struct buffer *buffer)
153{
154 struct gc_arena gc = gc_new();
155 const char *err_reason = "";
156
157 /* Example message: ACC,muppets,15,A,I am Miss Piggy */
158 struct buffer buf = *buffer;
159
160 const struct tls_multi *multi = c->c2.tls_multi;
161 if (!multi->acc_negotiated_protocols)
162 {
163 err_reason = "ACC not enabled or no negotiated protocols";
164 goto err;
165 }
166
167 if (!buf_advance(&buf, strlen("ACC")) || buf_read_u8(&buf) != ',')
168 {
169 err_reason = "missing , after ACC";
170 goto err;
171 }
172
173 /* extract protocol, payload length, flags substrings */
174 const char *protocol = buf_extract_field(&buf, ',', &gc);
175 if (!protocol)
176 {
177 err_reason = "could not extract protocol field";
178 goto err;
179 }
180
182 {
183 struct buffer msg_buf = alloc_buf_gc(1024, &gc);
184 buf_printf(&msg_buf, "protocol '%s' not in list of negotiated protocols '%s'",
185 protocol, multi->acc_negotiated_protocols);
186 err_reason = buf_cstr(&msg_buf);
187
188
189 goto err;
190 }
191
192 /* We do not check the length here. We make no promises to support
193 * anything larger than our announced message length but according to
194 * the robustness principle
195 * ("be conservative in what you send, be liberal in what you accept" - RFC 793 and others)
196 * we accept also longer messages */
197
198 int payload_len;
199 const char *payload_len_str = buf_extract_field(&buf, ',', &gc);
200 if (!payload_len_str
201 || !atoi_constrained(payload_len_str, &payload_len, "acc_payload_len", 0, TLS_CHANNEL_BUF_SIZE - 1, D_PUSH_ERRORS))
202 {
203 err_reason = "could not extract payload length field";
204 goto err;
205 }
206
207 int flags = parse_acc_message_flags_buf(&buf, &err_reason, &gc);
208
209 if (flags < 0)
210 {
211 goto err;
212 }
213
214 /* We should have a final NUL byte in the control message buffer
215 * and thus the length of the buffer should be payload_len + 1 */
216 if (buf_len(&buf) != payload_len + 1)
217 {
218 char *tmp = gc_malloc(512, 1, &gc);
219 snprintf(tmp, 512, "field length %d, payload length %d mismatch",
220 payload_len, buf_len(&buf) - 1);
221 err_reason = tmp;
222 goto err;
223 }
224
225
226 log_acc_message(c, &buf, payload_len, protocol, flags);
227 gc_free(&gc);
228 return;
229
230err:
231 msg(D_PUSH_ERRORS, "WARNING: Received malformed custom app control channel "
232 "message (%s): %s",
233 err_reason,
234 format_hex(CBPTR(buffer), BLEN(buffer), 80, &gc));
235 gc_free(&gc);
236}
237
238
239bool
241 struct tls_multi *multi,
242 struct tls_session *session,
243 const char *protocol, bool fragment,
244 const char *acc_msg_payload, bool base64)
245{
246 /*
247 * length of the protocol string + one ','
248 * 2 for the encoding (A or 6), potential F (fragment), and 1 for the ',',
249 * 4 for the message size itself and one comma
250 * 1 for the comma before the message itself */
251 const size_t max_header_size = strlen("ACC,") + strlen(protocol) + 1 + 4 + 1 + 2 + 1;
252 size_t len = max_header_size + strlen(acc_msg_payload);
253
255 {
256 msg(M_CLIENT, "message length (%zu) exceeds maximum possible message length (%d)", len, TLS_CHANNEL_BUF_SIZE);
257 return false;
258 }
259
260 if ((int)len > multi->acc_max_message_length)
261 {
262 msg(M_CLIENT, "header (%zu) + message size (%zu) length (%zu) exceeds "
263 "maximum allowed length negotiated with peer (%d)",
264 max_header_size, strlen(acc_msg_payload), len,
266 return false;
267 }
268
269 struct gc_arena gc = gc_new();
270 /* add 1 for the final \0 */
271 struct buffer buf = alloc_buf_gc(len + 1, &gc);
272
273 /* Example message: ACC,muppets,15,A,I am Miss Piggy */
274 buf_printf(&buf, "ACC,%s,%zu,%s%s,%s", protocol,
275 strlen(acc_msg_payload),
276 base64 ? "6" : "A",
277 fragment ? "F" : "",
278 acc_msg_payload);
279
282 gc_free(&gc);
283 return ret;
284}
285
286char *
287parse_acc_parameters(const char *capabilities,
288 const char *delim,
289 int *max_acc_len,
290 bool server,
291 struct gc_arena *gc)
292{
293 char *tmp_message = string_alloc(capabilities, NULL);
294 char *tmp_message_orig = tmp_message;
295 char *lasts = NULL;
296
297 const char *token = strtok_r(tmp_message, delim, &lasts);
298
299 int p = 0;
300 int acclen = 0;
301 const char *protocols = NULL;
302 char *ret = NULL;
303
304 /* In server mode we allow more capabilities than our own, in client
305 * mode we reject if we should use capabilities that we do not support */
306 int allowed_acc_len = server ? INT_MAX : ACC_MAX_MSG_LEN;
307
308 while (token)
309 {
310 if (p == 0 && !atoi_constrained(token, &acclen, "ACC message length", ACC_MIN_MSG_LEN, allowed_acc_len, D_PUSH_ERRORS))
311 {
312 goto done;
313 }
314
315 if (p == 1 && (!tls_item_in_cipher_list("A", token) || !tls_item_in_cipher_list("6", token)))
316 {
317 msg(D_PUSH_ERRORS, "App custom control encoding must include base64 and ascii");
318 goto done;
319 }
320
321 if (p == 1 && !server && strcmp(token, "A:6") && strcmp(token, "6:A"))
322 {
323 msg(D_PUSH_ERRORS, "App custom control encoding must be exactly base64 and ascii");
324 goto done;
325 }
326
327 if (p == 2)
328 {
329 protocols = token;
330 }
331
332 if (p == 3)
333 {
334 msg(D_PUSH_ERRORS, "Too many parameters for INFO ACC message/IV_ACC.");
335 goto done;
336 }
337
338 token = strtok_r(NULL, delim, &lasts);
339 p++;
340 }
341
342 *max_acc_len = min_int(acclen, ACC_MAX_MSG_LEN);
343 ret = string_alloc(protocols, gc);
344
345done:
346 free(tmp_message_orig);
347 return ret;
348}
349
350struct buffer
351get_list_intersection(struct gc_arena *gc, const char *list1, const char *list2)
352{
353 char *tmp = string_alloc(list1, NULL);
354 char *lasts = NULL;
355 const char *token = strtok_r(tmp, ":", &lasts);
356
357 /* The maximum possible length is the shorter of the two input lists */
358 size_t max_len = min_size(strlen(list1), strlen(list2));
359
360 struct buffer common_protocols = alloc_buf_gc(max_len + 1, gc);
361
362 while (token)
363 {
364 /* check for every items is in both lists and not already in the
365 * common list */
366 if (tls_item_in_cipher_list(token, list2)
367 && !tls_item_in_cipher_list(token, buf_cstr(&common_protocols)))
368 {
369 if (buf_len(&common_protocols) > 0)
370 {
371 buf_write_u8(&common_protocols, ':');
372 }
373 buf_printf(&common_protocols, "%s", token);
374 }
375 token = strtok_r(NULL, ":", &lasts);
376 }
377 free(tmp);
378 return common_protocols;
379}
380
381void
383{
384 if (!multi->opt.acc_protocols)
385 {
386 /* No app custom protocols have been configured server-side. */
387 return;
388 }
389
390 if (multi->acc_negotiated_protocols)
391 {
392 /* We already have determined the common protocols. */
393 return;
394 }
395
396 struct gc_arena gc = gc_new();
397
398 /* example IV_ACC: IV_ACC=2048,6:A,flower:power */
399 const char *peer_info = multi->peer_info;
400 const char *iv_acc = extract_var_peer_info(peer_info, "IV_ACC=", &gc);
401 if (!iv_acc)
402 {
403 gc_free(&gc);
404 return;
405 }
406
407 int max_acc_len = 0;
408 const char *protocols = parse_acc_parameters(iv_acc, ",", &max_acc_len, true, &gc);
409
410 if (!protocols)
411 {
412 gc_free(&gc);
413 msg(D_PUSH_ERRORS, "WARNING: IV_ACC peer info variable of peer is malformed");
414 return;
415 }
416
417 struct buffer common_protocols = get_list_intersection(&gc, multi->opt.acc_protocols, protocols);
418
419 if (buf_len(&common_protocols) == 0)
420 {
421 msg(D_PUSH_DEBUG, "WARNING: No common app custom control protocol.");
422 gc_free(&gc);
423 return;
424 }
425
426 multi->acc_negotiated_protocols = string_alloc(buf_str(&common_protocols), NULL);
427 multi->acc_max_message_length = max_acc_len;
428
429 setenv_str(session->opt->es, "acc_protocols", multi->acc_negotiated_protocols);
430 setenv_int(session->opt->es, "acc_message_len", multi->acc_max_message_length);
431
432 gc_free(&gc);
433}
434
435void
437{
438#ifdef ENABLE_MANAGEMENT
439 if (management)
440 {
441 msg(M_CLIENT, ">ACC_PROTOCOLS:protocols=%s,message_len=%d",
443 }
444#endif
445}
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
static int parse_acc_message_flags_buf(struct buffer *buf, const char **err_reason, struct gc_arena *gc)
Wrapper around parse_acc_message_flags to also include the step of extracting the flags from the buff...
Definition acc.c:139
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
int parse_acc_message_flags(const char *flags, const char **err_reason, struct gc_arena *gc)
Parses the flags field of an app control message If there is an error parsing the flags field the met...
Definition acc.c:91
static void log_acc_message(struct context *c, const struct buffer *buf, int payload_len, const char *protocol, int flags)
Definition acc.c:43
void notify_client_acc_protocols(struct tls_multi *multi)
Notifies a client via management interface of the negotiated app custom protocols.
Definition acc.c:436
#define ACC_MIN_MSG_LEN
Definition acc.h:31
#define ACC_MAX_MSG_LEN
Definition acc.h:32
@ ACC_MESSAGE_FLAGS_FRAGMENT
Definition acc.h:100
@ ACC_MESSAGE_FLAGS_BASE64
Definition acc.h:99
@ ACC_MESSAGE_FLAGS_ASCII
Definition acc.h:98
bool buf_printf(struct buffer *buf, const char *format,...)
printf-style append to a buffer with overflow check.
Definition buffer.c:226
char * buf_extract_field(struct buffer *buf, char sep, struct gc_arena *gc)
Extract a field from buf that ends with the sep character.
Definition buffer.c:1383
void * gc_malloc(size_t size, bool clear, struct gc_arena *a)
Allocate memory and, optionally, zero it.
Definition buffer.c:313
struct buffer alloc_buf_gc(size_t size, struct gc_arena *gc)
Allocate a buffer of the given size under garbage collection.
Definition buffer.c:77
void gc_addspecial(void *addr, void(*free_function)(void *), struct gc_arena *a)
Register an address with a custom free function in a garbage collection arena.
Definition buffer.c:406
char * string_alloc(const char *str, struct gc_arena *gc)
Duplicate a string, allocating memory under garbage collection.
Definition buffer.c:601
Buffer management functions and garbage collection.
#define BSTR(buf)
Return the buffer content pointer cast to char *.
Definition buffer.h:157
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
#define CBPTR(buf)
Return a const pointer to the start of the buffer content.
Definition buffer.h:141
static bool buf_advance(struct buffer *buf, ssize_t size)
Advance the content start of a buffer, consuming bytes from the front.
Definition buffer.h:1165
static bool buf_write_u8(struct buffer *dest, uint8_t data)
Append a uint8_t to a buffer.
Definition buffer.h:1283
static int buf_read_u8(struct buffer *buf)
Read and consume a uint8_t from the front of a buffer.
Definition buffer.h:1490
#define BLEN(buf)
Return the length of the buffer content in bytes.
Definition buffer.h:151
static char * format_hex(const uint8_t *data, size_t size, size_t maxoutput, struct gc_arena *gc)
Format a binary buffer as a hex string with spaces every 4 bytes.
Definition buffer.h:960
static void gc_free(struct gc_arena *a)
Free all allocations in a garbage collection arena.
Definition buffer.h:1965
#define CBSTR(buf)
Return the buffer content pointer cast to const char *.
Definition buffer.h:159
static struct gc_arena gc_new(void)
Allocate and return a new, empty garbage collection arena.
Definition buffer.h:1949
static char * buf_str(struct buffer *buf)
Return the buffer content pointer cast to char *.
Definition buffer.h:572
#define TLS_CHANNEL_BUF_SIZE
Definition common.h:70
char * strtok_r(char *s, const char *delim, char **last)
void setenv_int(struct env_set *es, const char *name, int value)
Definition env_set.c:289
void setenv_str(struct env_set *es, const char *name, const char *value)
Definition env_set.c:305
#define D_PUSH
Definition errlevel.h:82
#define D_PUSH_DEBUG
Definition errlevel.h:149
#define D_PUSH_ERRORS
Definition errlevel.h:66
void reschedule_multi_process(struct context *c)
Reschedule tls_multi_process.
Definition forward.c:402
bool send_control_channel_string_dowork(struct tls_session *session, const char *str, msglvl_t msglevel)
Definition forward.c:381
Interface functions to the internal and external multiplexers.
#define TM_ACTIVE
Active tls_session.
Definition ssl_common.h:552
static size_t min_size(size_t x, size_t y)
Definition integer.h:79
static int min_int(int x, int y)
Definition integer.h:105
Header file for server-mode related structures and functions.
#define M_CLIENT
Definition error.h:108
#define msg(flags,...)
Definition error.h:152
#define ASSERT(x)
Definition error.h:221
#define MODE_SERVER
Definition options.h:265
bool atoi_constrained(const char *str, int *value, const char *name, int min, int max, msglvl_t msglevel)
Converts a str to an integer if the string can be represented as an integer number and is between min...
int openvpn_base64_encode(const void *data, int size, char **str)
Definition base64.c:51
static const struct key_state * get_primary_key(const struct tls_multi *multi)
gets an item of key_state objects in the order they should be scanned by data channel modules.
Definition ssl_common.h:771
bool tls_item_in_cipher_list(const char *item, const char *list)
Return true iff item is present in the colon-separated zero-terminated cipher list.
Definition ssl_ncp.c:197
Control Channel SSL/Data dynamic negotiation Module This file is split from ssl.h to be able to unit ...
char * extract_var_peer_info(const char *peer_info, const char *var, struct gc_arena *gc)
Extracts a variable from peer info, the returned string will be allocated using the supplied gc_arena...
Definition ssl_util.c:63
SSL utility functions.
Wrapper structure for dynamically allocated memory.
Definition buffer.h:71
int len
Length in bytes of the actual content within the allocated memory.
Definition buffer.h:76
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
Structure for reassembling one incoming fragmented packet.
Definition fragment.h:65
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:127
unsigned int mda_key_id
Definition ssl_common.h:263
unsigned long cid
Definition manage.h:64
unsigned int flags
Definition manage.h:69
int mode
Definition options.h:266
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
const char * acc_protocols
The app custom control protocols we should announce as supported.
Definition ssl_common.h:462
Security parameter state of a single session within a VPN tunnel.
Definition ssl_common.h:497
struct gc_arena gc
Definition test_ssl.c:138