Attention is currently required from: cron2.
Hello cron2,
I'd like you to reexamine a change. Please visit
http://gerrit.openvpn.net/c/openvpn/+/1800?usp=email
to look at the new patch set (#5).
Change subject: Allow extracing other integers from peer info and add a unit
test for it
......................................................................
Allow extracing other integers from peer info and add a unit test for it
This also ensure that we only really extract the variable we are looking
for. The old code would also consider UV_IV_NCP to be IV_NCP.
Change-Id: Iad94e7a9d0b3be8a8db09e9a20eaac6041470ab6
Signed-off-by: Arne Schwabe <[email protected]>
---
M CMakeLists.txt
M src/openvpn/push.c
M src/openvpn/ssl_ncp.c
M src/openvpn/ssl_util.c
M src/openvpn/ssl_util.h
M tests/unit_tests/openvpn/Makefile.am
M tests/unit_tests/openvpn/test_push_update_msg.c
M tests/unit_tests/openvpn/test_ssl.c
8 files changed, 159 insertions(+), 50 deletions(-)
git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/00/1800/5
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7473f15..21bcb91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -908,7 +908,8 @@
src/openvpn/options_util.c
src/openvpn/otime.c
src/openvpn/list.c
- )
+ src/openvpn/ssl_util.c
+ )
target_sources(test_argv PRIVATE
tests/unit_tests/openvpn/mock_get_random.c
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index 633c007d..ce2baf2 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -718,9 +718,9 @@
/* Push our mtu to the peer if it supports pushable MTUs */
int client_max_mtu = 0;
- const char *iv_mtu = extract_var_peer_info(tls_multi->peer_info,
"IV_MTU=", gc);
+ unsigned int iv_mtu = peer_info_extract_uint(tls_multi->peer_info,
"IV_MTU=");
- if (iv_mtu && sscanf(iv_mtu, "%d", &client_max_mtu) == 1)
+ if (iv_mtu != 0)
{
push_option_fmt(gc, push_list, M_USAGE, "tun-mtu %d", o->ce.tun_mtu);
if (client_max_mtu < o->ce.tun_mtu)
diff --git a/src/openvpn/ssl_ncp.c b/src/openvpn/ssl_ncp.c
index b450de8..8b0f28d 100644
--- a/src/openvpn/ssl_ncp.c
+++ b/src/openvpn/ssl_ncp.c
@@ -55,20 +55,10 @@
* Return the Negotiable Crypto Parameters version advertised in the peer info
* string, or 0 if none specified.
*/
-static int
+static unsigned int
tls_peer_info_ncp_ver(const char *peer_info)
{
- const char *ncpstr = peer_info ? strstr(peer_info, "IV_NCP=") : NULL;
- if (ncpstr)
- {
- int ncp = 0;
- int r = sscanf(ncpstr, "IV_NCP=%d", &ncp);
- if (r == 1)
- {
- return ncp;
- }
- }
- return 0;
+ return peer_info_extract_uint(peer_info, "IV_NCP=");
}
/**
diff --git a/src/openvpn/ssl_util.c b/src/openvpn/ssl_util.c
index 2f01f8a..ba185c1 100644
--- a/src/openvpn/ssl_util.c
+++ b/src/openvpn/ssl_util.c
@@ -27,26 +27,56 @@
#include "openvpn.h"
#include "ssl_util.h"
-char *
-extract_var_peer_info(const char *peer_info, const char *var, struct gc_arena
*gc)
+/**
+ * Looks for the string field at the start of peer_info or
+ * after any new line and returns a pointer to the start of the field
+ * or NULL if not found.
+ */
+static const char *
+peer_info_extract_varstr(const char *peer_info, const char *field)
{
if (!peer_info)
{
return NULL;
}
- const char *var_start = strstr(peer_info, var);
+ while (peer_info)
+ {
+ /* peer info starts with this field */
+ if (strncmp(peer_info, field, strlen(field)) == 0)
+ {
+ return peer_info;
+ }
+
+ /* skip to the next line */
+ peer_info = strchr(peer_info, '\n');
+ if (peer_info)
+ {
+ /* skip the '\n' itself */
+ peer_info++;
+ }
+ }
+ return NULL;
+}
+
+char *
+extract_var_peer_info(const char *peer_info, const char *var, struct gc_arena
*gc)
+{
+ const char *var_start = peer_info_extract_varstr(peer_info, var);
if (!var_start)
{
- /* variable not found in peer info */
+ /* variable hasn't been found in peer info */
return NULL;
}
+ /* skip over the variable name (includes the = as per API)*/
var_start += strlen(var);
- const char *var_end = strstr(var_start, "\n");
+
+ /* returns the location of the next '\n' or the end of the
+ * string if the variable is already on the last line */
+ const char *var_end = strchr(var_start, '\n');
if (!var_end)
{
- /* var is at end of the peer_info list and no '\n' follows */
var_end = var_start + strlen(var_start);
}
@@ -56,38 +86,40 @@
return var_value;
}
+
unsigned int
-extract_iv_proto(const char *peer_info)
+peer_info_extract_int(const char *peer_info, const char *field, const char
*format, unsigned int default_value)
{
- const char *optstr = peer_info ? strstr(peer_info, "IV_PROTO=") : NULL;
+ const char *optstr = peer_info_extract_varstr(peer_info, field);
if (optstr)
{
- int proto = 0;
- int r = sscanf(optstr, "IV_PROTO=%d", &proto);
- if (r == 1 && proto > 0)
+ optstr += strlen(field);
+
+ int value = 0;
+ int r = sscanf(optstr, format, &value);
+ if (r == 1 && value >= 0)
{
- return proto;
+ return value;
}
}
- return 0;
+ return default_value;
+}
+
+unsigned int
+peer_info_extract_uint(const char *peer_info, const char *field)
+{
+ return peer_info_extract_int(peer_info, field, "%u", 0);
}
uint32_t
extract_asymmetric_peer_id(const char *peer_info)
{
- for (const char *p = peer_info; p && (p = strstr(p, "ID=")); p += 3)
+ uint32_t peer_id = peer_info_extract_int(peer_info, "ID=", "%x",
MAX_PEER_ID);
+ if (peer_id < MAX_PEER_ID)
{
- /* only accept "ID=" at the start of a line, so it does not match
- * substrings like "UV_ID=" or "GUID=" */
- if (p == peer_info || p[-1] == '\n')
- {
- uint32_t peer_id = 0;
- if (sscanf(p, "ID=%x", &peer_id) == 1 && peer_id < MAX_PEER_ID)
- {
- return peer_id;
- }
- }
+ return peer_id;
}
+
return MAX_PEER_ID;
}
diff --git a/src/openvpn/ssl_util.h b/src/openvpn/ssl_util.h
index 1a69e6f..6f9f65b 100644
--- a/src/openvpn/ssl_util.h
+++ b/src/openvpn/ssl_util.h
@@ -33,11 +33,33 @@
#include "buffer.h"
/**
+ * Extracts the named integer variable and returns its value or default_value
+ * if it cannot be extracted.
+ *
+ * @param peer_info peer info string to search in
+ * @param field name of the field to be extracted including the =
+ * @param format sscanf/printf format string of the type to extract
+ * @param default_value default value to return if the field cannot be
extracted
+ */
+unsigned int
+peer_info_extract_int(const char *peer_info, const char *field, const char
*format, unsigned int default_value);
+
+/**
+ * Extracts the named integer variable and returns its value or 0
+ * if it cannot be extracted.
+ *
+ * @param peer_info peer info string to search in
+ * @param field name of the field to be extracted
+ */
+unsigned int
+peer_info_extract_uint(const char *peer_info, const char *field);
+
+/**
* Extracts a variable from peer info, the returned string will be allocated
* using the supplied gc_arena
*
* @param peer_info The peer's peer_info
- * @param var The variable *including* =, e.g. IV_CIPHERS=
+ * @param var The variable including =, e.g. IV_CIPHERS=
* @param gc GC arena to allocate return value in
*
* @return The content of the variable as NULL terminated string or NULL if
the
@@ -51,8 +73,11 @@
*
* @param peer_info peer info string to search for IV_PROTO
*/
-unsigned int extract_iv_proto(const char *peer_info);
-
+static inline unsigned int
+extract_iv_proto(const char *peer_info)
+{
+ return peer_info_extract_uint(peer_info, "IV_PROTO=");
+}
/**
* Extracts the ID variable and returns its value or
diff --git a/tests/unit_tests/openvpn/Makefile.am
b/tests/unit_tests/openvpn/Makefile.am
index d861ef9..5ccf3ce 100644
--- a/tests/unit_tests/openvpn/Makefile.am
+++ b/tests/unit_tests/openvpn/Makefile.am
@@ -395,7 +395,8 @@
$(top_srcdir)/src/openvpn/platform.c \
$(top_srcdir)/src/openvpn/options_util.c \
$(top_srcdir)/src/openvpn/otime.c \
- $(top_srcdir)/src/openvpn/list.c
+ $(top_srcdir)/src/openvpn/list.c \
+ $(top_srcdir)/src/openvpn/ssl_util.c
socket_testdriver_CFLAGS = \
-I$(top_srcdir)/include -I$(top_srcdir)/src/compat
-I$(top_srcdir)/src/openvpn \
diff --git a/tests/unit_tests/openvpn/test_push_update_msg.c
b/tests/unit_tests/openvpn/test_push_update_msg.c
index 219b476..389fa09 100644
--- a/tests/unit_tests/openvpn/test_push_update_msg.c
+++ b/tests/unit_tests/openvpn/test_push_update_msg.c
@@ -188,12 +188,6 @@
{
return true;
}
-
-unsigned int
-extract_iv_proto(const char *peer_info)
-{
- return IV_PROTO_PUSH_UPDATE;
-}
#endif /* ifdef ENABLE_MANAGEMENT */
/* tests */
@@ -650,6 +644,7 @@
m->instances = calloc(1, sizeof(struct multi_instance *));
struct multi_instance *mi = calloc(1, sizeof(struct multi_instance));
mi->context.c2.tls_multi = calloc(1, sizeof(struct tls_multi));
+ mi->context.c2.tls_multi->peer_info = "IV_PROTO=4096"; //
IV_PROTO_PUSH_UPDATE
*(m->instances) = mi;
m->top.options.disable_dco = true;
*state = m;
diff --git a/tests/unit_tests/openvpn/test_ssl.c
b/tests/unit_tests/openvpn/test_ssl.c
index 0e9cecf..03544ea 100644
--- a/tests/unit_tests/openvpn/test_ssl.c
+++ b/tests/unit_tests/openvpn/test_ssl.c
@@ -48,7 +48,9 @@
#include "buffer.h"
#include "cert_data.h"
#include "packet_id.h"
+#include "ssl_util.h"
#include "ssl_verify.h"
+#include "openvpn.h"
/* Mock function to be allowed to include win32.c which is required for
* getting the temp directory */
@@ -829,6 +831,68 @@
free_certificate(cert);
}
+void
+ssl_test_extract_peer_info(void **state)
+{
+ const char *peer_info_normal =
+ "IV_VER=2.6_git\nIV_PLAT=mac\nIV_TCPNL=1\nIV_NCP=2\n"
+ "IV_CIPHERS=AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305\n"
+ "IV_PROTO=94\nIV_LZO_STUB=1\nIV_COMP_STUB=1\nP=78\nIV_COMP_STUBv2=1\n"
+ "IV_SSL=OpenSSL_3.0.5_5_Jul_2022\nIV_LZ4v2=1";
+
+ const char *empty = "";
+ const char *invalid_proto = "IV_PROTO=seven\nIV_SSL=7\nP=300\nID=xyz";
+ const char *test_prefix = "UV_IV_PROTO=773\nNP=112\nPD=8\n";
+
+
+ assert_int_equal(extract_iv_proto(peer_info_normal), 94);
+ assert_int_equal(extract_iv_proto(empty), 0);
+ assert_int_equal(extract_iv_proto(invalid_proto), 0);
+ /* This should not pick up the UV_IV_PROTO that has the extra prefix */
+ assert_int_equal(extract_iv_proto(test_prefix), 0);
+
+ assert_int_equal(peer_info_extract_uint(peer_info_normal,
"IV_COMP_STUB="), 1);
+ assert_int_equal(peer_info_extract_int(empty, "IV_COMP_STUB=", "%d",
0xfe0d0d), 0xfe0d0d);
+ assert_int_equal(peer_info_extract_uint(invalid_proto, "IV_COMP_STUB="),
0);
+
+ assert_int_equal(peer_info_extract_int(test_prefix, "NP=", "%d", 23), 112);
+ assert_int_equal(peer_info_extract_uint(test_prefix, "PD="), 8);
+ assert_int_equal(peer_info_extract_int(test_prefix, "P=", "%x", 0xfe0d0d),
0xfe0d0d);
+ assert_int_equal(peer_info_extract_uint(peer_info_normal, "P="), 78);
+ assert_int_equal(peer_info_extract_uint(test_prefix, "UV_IV_PROTO="), 773);
+
+ struct gc_arena gc = gc_new();
+
+ const char *peer_ciphers = extract_var_peer_info(peer_info_normal,
"IV_CIPHERS=", &gc);
+ assert_string_equal(peer_ciphers,
"AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305");
+
+ /* with the extra = this should not extract anything */
+ const char *proto = extract_var_peer_info(peer_info_normal, "IV_PROTO==",
&gc);
+ assert_null(proto);
+
+ proto = extract_var_peer_info(peer_info_normal, "IV_PROTO=", &gc);
+ assert_string_equal(proto, "94");
+
+
+ const char *double_eq_info = "FOO=7\nFOO==new";
+ const char *foo_eq = extract_var_peer_info(double_eq_info, "FOO=", &gc);
+ const char *foo = extract_var_peer_info(double_eq_info, "FOO", &gc);
+ const char *foo_2eq = extract_var_peer_info(double_eq_info, "FOO==", &gc);
+
+ assert_string_equal(foo, "=7");
+ assert_string_equal(foo_eq, "7");
+ assert_string_equal(foo_2eq, "new");
+
+ assert_int_equal(extract_asymmetric_peer_id(double_eq_info), MAX_PEER_ID);
+ assert_int_equal(extract_asymmetric_peer_id(peer_info_normal),
MAX_PEER_ID);
+ assert_int_equal(extract_asymmetric_peer_id(invalid_proto), MAX_PEER_ID);
+ assert_int_equal(extract_asymmetric_peer_id("ID=f7"), 0xf7);
+ assert_int_equal(extract_asymmetric_peer_id("X=foo\nID=12ab"), 0x12ab);
+ assert_int_equal(extract_asymmetric_peer_id("X=foo\nID=34dd\nY=bar"),
0x34dd);
+ assert_int_equal(extract_asymmetric_peer_id("X=foo\nID=12345678"),
MAX_PEER_ID);
+
+ gc_free(&gc);
+}
int
main(void)
@@ -853,7 +917,8 @@
cmocka_unit_test(test_data_channel_roundtrip_bf_cbc),
cmocka_unit_test(test_data_channel_known_vectors_epoch),
cmocka_unit_test(test_data_channel_known_vectors_shortpktid),
- cmocka_unit_test(crypto_test_print_cert_details)
+ cmocka_unit_test(crypto_test_print_cert_details),
+ cmocka_unit_test(ssl_test_extract_peer_info)
};
--
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1800?usp=email
To unsubscribe, or for help writing mail filters, visit
http://gerrit.openvpn.net/settings?usp=email
Gerrit-MessageType: newpatchset
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: Iad94e7a9d0b3be8a8db09e9a20eaac6041470ab6
Gerrit-Change-Number: 1800
Gerrit-PatchSet: 5
Gerrit-Owner: plaisthos <[email protected]>
Gerrit-Reviewer: cron2 <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: cron2 <[email protected]>
_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel