Browse code

cleanup: merge packet_id_alloc_outgoing() into packet_id_write()

The functions packet_id_alloc_outgoing() and packet_id_write() were
always called in tandem. Instead of forcing the caller to allocate a
packet_id_net to do so, merge the two functions. This simplifies the API
and reduces the chance on mistakes in the future.

This patch adds unit tests to verify the behaviour of packet_id_write().
Verifying that we assert out correctly required the change to mock_msg.c.

Signed-off-by: Steffan Karger <steffan.karger@fox-it.com>
Acked-by: Gert Doering <gert@greenie.muc.de>
Acked-by: David Sommerseth <davids@openvpn.net>
Message-Id: <1494006291-3522-1-git-send-email-steffan.karger@fox-it.com>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg14541.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Steffan Karger authored on 2017/05/06 02:44:51
Showing 7 changed files
... ...
@@ -85,7 +85,6 @@ openvpn_encrypt_aead(struct buffer *buf, struct buffer work,
85 85
     /* Prepare IV */
86 86
     {
87 87
         struct buffer iv_buffer;
88
-        struct packet_id_net pin;
89 88
         uint8_t iv[OPENVPN_MAX_IV_LENGTH] = {0};
90 89
         const int iv_len = cipher_ctx_iv_length(ctx->cipher);
91 90
 
... ...
@@ -94,8 +93,7 @@ openvpn_encrypt_aead(struct buffer *buf, struct buffer work,
94 94
         buf_set_write(&iv_buffer, iv, iv_len);
95 95
 
96 96
         /* IV starts with packet id to make the IV unique for packet */
97
-        packet_id_alloc_outgoing(&opt->packet_id.send, &pin, false);
98
-        ASSERT(packet_id_write(&pin, &iv_buffer, false, false));
97
+        ASSERT(packet_id_write(&opt->packet_id.send, &iv_buffer, false, false));
99 98
 
100 99
         /* Remainder of IV consists of implicit part (unique per session) */
101 100
         ASSERT(buf_write(&iv_buffer, ctx->implicit_iv, ctx->implicit_iv_len));
... ...
@@ -195,22 +193,20 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work,
195 195
                 /* Put packet ID in plaintext buffer */
196 196
                 if (packet_id_initialized(&opt->packet_id))
197 197
                 {
198
-                    struct packet_id_net pin;
199
-                    packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM));
200
-                    ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true));
198
+                    ASSERT(packet_id_write(&opt->packet_id.send, buf,
199
+                                           opt->flags & CO_PACKET_ID_LONG_FORM,
200
+                                           true));
201 201
                 }
202 202
             }
203 203
             else if (cipher_kt_mode_ofb_cfb(cipher_kt))
204 204
             {
205
-                struct packet_id_net pin;
206 205
                 struct buffer b;
207 206
 
208 207
                 /* packet-ID required for this mode. */
209 208
                 ASSERT(packet_id_initialized(&opt->packet_id));
210 209
 
211
-                packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true);
212 210
                 buf_set_write(&b, iv_buf, iv_size);
213
-                ASSERT(packet_id_write(&pin, &b, true, false));
211
+                ASSERT(packet_id_write(&opt->packet_id.send, &b, true, false));
214 212
             }
215 213
             else /* We only support CBC, CFB, or OFB modes right now */
216 214
             {
... ...
@@ -257,9 +253,9 @@ openvpn_encrypt_v1(struct buffer *buf, struct buffer work,
257 257
         {
258 258
             if (packet_id_initialized(&opt->packet_id))
259 259
             {
260
-                struct packet_id_net pin;
261
-                packet_id_alloc_outgoing(&opt->packet_id.send, &pin, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM));
262
-                ASSERT(packet_id_write(&pin, buf, BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM), true));
260
+                ASSERT(packet_id_write(&opt->packet_id.send, buf,
261
+                        BOOL_CAST(opt->flags & CO_PACKET_ID_LONG_FORM),
262
+                        true));
263 263
             }
264 264
             if (ctx->hmac)
265 265
             {
... ...
@@ -325,12 +325,30 @@ packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form)
325 325
     return true;
326 326
 }
327 327
 
328
+static void
329
+packet_id_send_update(struct packet_id_send *p, bool long_form)
330
+{
331
+    if (!p->time)
332
+    {
333
+        p->time = now;
334
+    }
335
+    p->id++;
336
+    if (!p->id)
337
+    {
338
+        ASSERT(long_form);
339
+        p->time = now;
340
+        p->id = 1;
341
+    }
342
+}
343
+
328 344
 bool
329
-packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend)
345
+packet_id_write(struct packet_id_send *p, struct buffer *buf, bool long_form,
346
+        bool prepend)
330 347
 {
331
-    packet_id_type net_id = htonpid(pin->id);
332
-    net_time_t net_time = htontime(pin->time);
348
+    packet_id_send_update(p, long_form);
333 349
 
350
+    const packet_id_type net_id = htonpid(p->id);
351
+    const net_time_t net_time = htontime(p->time);
334 352
     if (prepend)
335 353
     {
336 354
         if (long_form)
... ...
@@ -254,7 +254,18 @@ const char *packet_id_persist_print(const struct packet_id_persist *p, struct gc
254 254
 
255 255
 bool packet_id_read(struct packet_id_net *pin, struct buffer *buf, bool long_form);
256 256
 
257
-bool packet_id_write(const struct packet_id_net *pin, struct buffer *buf, bool long_form, bool prepend);
257
+/**
258
+ * Write a packet ID to buf, and update the packet ID state.
259
+ *
260
+ * @param p             Packet ID state.
261
+ * @param buf           Buffer to write the packet ID too
262
+ * @param long_form     If true, also update and write time_t to buf
263
+ * @param prepend       If true, prepend to buffer, otherwise apppend.
264
+ *
265
+ * @return true if successful, false otherwise.
266
+ */
267
+bool packet_id_write(struct packet_id_send *p, struct buffer *buf,
268
+        bool long_form, bool prepend);
258 269
 
259 270
 /*
260 271
  * Inline functions.
... ...
@@ -304,28 +315,6 @@ packet_id_close_to_wrapping(const struct packet_id_send *p)
304 304
     return p->id >= PACKET_ID_WRAP_TRIGGER;
305 305
 }
306 306
 
307
-/*
308
- * Allocate an outgoing packet id.
309
- * Sequence number ranges from 1 to 2^32-1.
310
- * In long_form, a time_t is added as well.
311
- */
312
-static inline void
313
-packet_id_alloc_outgoing(struct packet_id_send *p, struct packet_id_net *pin, bool long_form)
314
-{
315
-    if (!p->time)
316
-    {
317
-        p->time = now;
318
-    }
319
-    pin->id = ++p->id;
320
-    if (!pin->id)
321
-    {
322
-        ASSERT(long_form);
323
-        p->time = now;
324
-        pin->id = p->id = 1;
325
-    }
326
-    pin->time = p->time;
327
-}
328
-
329 307
 static inline bool
330 308
 check_timestamp_delta(time_t remote, unsigned int max_delta)
331 309
 {
... ...
@@ -98,11 +98,7 @@ tls_crypt_wrap(const struct buffer *src, struct buffer *dst,
98 98
          format_hex(BPTR(src), BLEN(src), 80, &gc));
99 99
 
100 100
     /* Get packet ID */
101
-    {
102
-        struct packet_id_net pin;
103
-        packet_id_alloc_outgoing(&opt->packet_id.send, &pin, true);
104
-        packet_id_write(&pin, dst, true, false);
105
-    }
101
+    ASSERT(packet_id_write(&opt->packet_id.send, dst, true, false));
106 102
 
107 103
     dmsg(D_PACKET_CONTENT, "TLS-CRYPT WRAP AD: %s",
108 104
          format_hex(BPTR(dst), BLEN(dst), 0, &gc));
... ...
@@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = foreign
3 3
 check_PROGRAMS=
4 4
 
5 5
 if HAVE_LD_WRAP_SUPPORT
6
-check_PROGRAMS += argv_testdriver buffer_testdriver
6
+check_PROGRAMS += argv_testdriver buffer_testdriver packet_id_testdriver
7 7
 endif
8 8
 
9 9
 if ENABLE_CRYPTO
... ...
@@ -31,6 +31,17 @@ buffer_testdriver_SOURCES = test_buffer.c mock_msg.c \
31 31
 	$(openvpn_srcdir)/buffer.c \
32 32
 	$(openvpn_srcdir)/platform.c
33 33
 
34
+packet_id_testdriver_CFLAGS  = @TEST_CFLAGS@ \
35
+	-I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \
36
+	$(OPTIONAL_CRYPTO_CFLAGS)
37
+packet_id_testdriver_LDFLAGS = @TEST_LDFLAGS@ \
38
+	$(OPTIONAL_CRYPTO_LIBS)
39
+packet_id_testdriver_SOURCES = test_packet_id.c mock_msg.c \
40
+	$(openvpn_srcdir)/buffer.c \
41
+	$(openvpn_srcdir)/otime.c \
42
+	$(openvpn_srcdir)/packet_id.c \
43
+	$(openvpn_srcdir)/platform.c
44
+
34 45
 tls_crypt_testdriver_CFLAGS  = @TEST_CFLAGS@ \
35 46
 	-I$(openvpn_includedir) -I$(compat_srcdir) -I$(openvpn_srcdir) \
36 47
 	$(OPTIONAL_CRYPTO_CFLAGS)
... ...
@@ -29,9 +29,12 @@
29 29
 #endif
30 30
 
31 31
 #include <stdarg.h>
32
-#include <stdbool.h>
32
+#include <stddef.h>
33 33
 #include <stdio.h>
34 34
 #include <stdlib.h>
35
+#include <setjmp.h>
36
+#include <cmocka.h>
37
+
35 38
 
36 39
 #include "errlevel.h"
37 40
 #include "error.h"
... ...
@@ -70,14 +73,8 @@ x_msg(const unsigned int flags, const char *format, ...)
70 70
 void
71 71
 assert_failed(const char *filename, int line, const char *condition)
72 72
 {
73
-    if (condition)
74
-    {
75
-        printf("Assertion failed at %s:%d (%s)", filename, line, condition);
76
-    }
77
-    else
78
-    {
79
-        printf("Assertion failed at %s:%d", filename, line);
80
-    }
73
+    mock_assert(false, condition ? condition : "", filename, line);
74
+    /* Keep compiler happy.  Should not happen, mock_assert() does not return */
81 75
     exit(1);
82 76
 }
83 77
 
84 78
new file mode 100644
... ...
@@ -0,0 +1,168 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP 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) 2016 Fox Crypto B.V. <openvpn@fox-it.com>
8
+ *
9
+ *  This program is free software; you can redistribute it and/or modify
10
+ *  it under the terms of the GNU General Public License version 2
11
+ *  as published by the Free Software Foundation.
12
+ *
13
+ *  This program is distributed in the hope that it will be useful,
14
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ *  GNU General Public License for more details.
17
+ *
18
+ *  You should have received a copy of the GNU General Public License
19
+ *  along with this program (see the file COPYING included with this
20
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
21
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
+ */
23
+
24
+#ifdef HAVE_CONFIG_H
25
+#include "config.h"
26
+#elif defined(_MSC_VER)
27
+#include "config-msvc.h"
28
+#endif
29
+
30
+#include "syshead.h"
31
+
32
+#include <stdarg.h>
33
+#include <stddef.h>
34
+#include <setjmp.h>
35
+#include <cmocka.h>
36
+
37
+#include "packet_id.h"
38
+
39
+#include "mock_msg.h"
40
+
41
+struct test_packet_id_write_data {
42
+    struct {
43
+        uint32_t buf_id;
44
+        uint32_t buf_time;
45
+    } test_buf_data;
46
+    struct buffer test_buf;
47
+    struct packet_id_send pis;
48
+};
49
+
50
+static int
51
+test_packet_id_write_setup(void **state) {
52
+    struct test_packet_id_write_data *data =
53
+            calloc(1, sizeof(struct test_packet_id_write_data));
54
+
55
+    if (!data)
56
+    {
57
+        return -1;
58
+    }
59
+
60
+    data->test_buf.data = (void *) &data->test_buf_data;
61
+    data->test_buf.capacity = sizeof(data->test_buf_data);
62
+
63
+    *state = data;
64
+    return 0;
65
+}
66
+
67
+static int
68
+test_packet_id_write_teardown(void **state) {
69
+    free(*state);
70
+    return 0;
71
+}
72
+
73
+static void
74
+test_packet_id_write_short(void **state)
75
+{
76
+    struct test_packet_id_write_data *data = *state;
77
+
78
+    now = 5010;
79
+    assert_true(packet_id_write(&data->pis, &data->test_buf, false, false));
80
+    assert_true(data->pis.id == 1);
81
+    assert_true(data->test_buf_data.buf_id == htonl(1));
82
+    assert_true(data->test_buf_data.buf_time == 0);
83
+}
84
+
85
+static void
86
+test_packet_id_write_long(void **state)
87
+{
88
+    struct test_packet_id_write_data *data = *state;
89
+
90
+    now = 5010;
91
+    assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
92
+    assert(data->pis.id == 1);
93
+    assert(data->pis.time == now);
94
+    assert_true(data->test_buf_data.buf_id == htonl(1));
95
+    assert_true(data->test_buf_data.buf_time == htonl(now));
96
+}
97
+
98
+static void
99
+test_packet_id_write_short_prepend(void **state)
100
+{
101
+    struct test_packet_id_write_data *data = *state;
102
+
103
+    data->test_buf.offset = sizeof(packet_id_type);
104
+    now = 5010;
105
+    assert_true(packet_id_write(&data->pis, &data->test_buf, false, true));
106
+    assert_true(data->pis.id == 1);
107
+    assert_true(data->test_buf_data.buf_id == htonl(1));
108
+    assert_true(data->test_buf_data.buf_time == 0);
109
+}
110
+
111
+static void
112
+test_packet_id_write_long_prepend(void **state)
113
+{
114
+    struct test_packet_id_write_data *data = *state;
115
+
116
+    data->test_buf.offset = sizeof(data->test_buf_data);
117
+    now = 5010;
118
+    assert_true(packet_id_write(&data->pis, &data->test_buf, true, true));
119
+    assert(data->pis.id == 1);
120
+    assert(data->pis.time == now);
121
+    assert_true(data->test_buf_data.buf_id == htonl(1));
122
+    assert_true(data->test_buf_data.buf_time == htonl(now));
123
+}
124
+
125
+static void
126
+test_packet_id_write_short_wrap(void **state)
127
+{
128
+    struct test_packet_id_write_data *data = *state;
129
+
130
+    data->pis.id = ~0;
131
+    expect_assert_failure(
132
+            packet_id_write(&data->pis, &data->test_buf, false, false));
133
+}
134
+
135
+static void
136
+test_packet_id_write_long_wrap(void **state)
137
+{
138
+    struct test_packet_id_write_data *data = *state;
139
+
140
+    data->pis.id = ~0;
141
+    now = 5010;
142
+    assert_true(packet_id_write(&data->pis, &data->test_buf, true, false));
143
+    assert(data->pis.id == 1);
144
+    assert(data->pis.time == now);
145
+    assert_true(data->test_buf_data.buf_id == htonl(1));
146
+    assert_true(data->test_buf_data.buf_time == htonl(now));
147
+}
148
+
149
+int
150
+main(void) {
151
+    const struct CMUnitTest tests[] = {
152
+            cmocka_unit_test_setup_teardown(test_packet_id_write_short,
153
+                    test_packet_id_write_setup, test_packet_id_write_teardown),
154
+            cmocka_unit_test_setup_teardown(test_packet_id_write_long,
155
+                    test_packet_id_write_setup, test_packet_id_write_teardown),
156
+            cmocka_unit_test_setup_teardown(test_packet_id_write_short_prepend,
157
+                    test_packet_id_write_setup, test_packet_id_write_teardown),
158
+            cmocka_unit_test_setup_teardown(test_packet_id_write_long_prepend,
159
+                    test_packet_id_write_setup, test_packet_id_write_teardown),
160
+            cmocka_unit_test_setup_teardown(test_packet_id_write_short_wrap,
161
+                    test_packet_id_write_setup, test_packet_id_write_teardown),
162
+            cmocka_unit_test_setup_teardown(test_packet_id_write_long_wrap,
163
+                    test_packet_id_write_setup, test_packet_id_write_teardown),
164
+    };
165
+
166
+    return cmocka_run_group_tests_name("packet_id tests", tests, NULL, NULL);
167
+}