Browse code

Add unit test for encrypting/decrypting data channel

This test is reusing code from --test-crypto but is modified to not rely
on the static key functionality and also only tests the most common
algorithm. So it does not yet completely replace --test-crypto

Change-Id: Ifa5ae96165d17b3cae4afc53e844bb34d1610e58
Acked-by: Frank Lichtenheld <frank@lichtenheld.com>
Message-Id: <20240208085749.869-1-gert@greenie.muc.de>
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg28195.html
Signed-off-by: Gert Doering <gert@greenie.muc.de>

Arne Schwabe authored on 2024/02/08 17:57:49
Showing 1 changed files
... ...
@@ -44,6 +44,9 @@
44 44
 #include "ssl_verify_backend.h"
45 45
 #include "win32.h"
46 46
 #include "test_common.h"
47
+#include "ssl.h"
48
+#include "buffer.h"
49
+#include "packet_id.h"
47 50
 
48 51
 /* Mock function to be allowed to include win32.c which is required for
49 52
  * getting the temp directory */
... ...
@@ -120,20 +123,238 @@ crypto_pem_encode_certificate(void **state)
120 120
     gc_free(&gc);
121 121
 }
122 122
 
123
+static void
124
+init_implicit_iv(struct crypto_options *co)
125
+{
126
+    cipher_ctx_t *cipher = co->key_ctx_bi.encrypt.cipher;
127
+
128
+    if (cipher_ctx_mode_aead(cipher))
129
+    {
130
+        size_t impl_iv_len = cipher_ctx_iv_length(cipher) - sizeof(packet_id_type);
131
+        ASSERT(cipher_ctx_iv_length(cipher) <= OPENVPN_MAX_IV_LENGTH);
132
+        ASSERT(cipher_ctx_iv_length(cipher) >= OPENVPN_AEAD_MIN_IV_LEN);
133
+
134
+        /* Generate dummy implicit IV */
135
+        ASSERT(rand_bytes(co->key_ctx_bi.encrypt.implicit_iv,
136
+                          OPENVPN_MAX_IV_LENGTH));
137
+        co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len;
138
+
139
+        memcpy(co->key_ctx_bi.decrypt.implicit_iv,
140
+               co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH);
141
+        co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len;
142
+    }
143
+}
144
+
145
+static void
146
+init_frame_parameters(struct frame *frame)
147
+{
148
+    int overhead = 0;
149
+
150
+    /* tls-auth and tls-crypt */
151
+    overhead += 128;
152
+
153
+    /* TCP length field and opcode */
154
+    overhead += 3;
155
+
156
+    /* ACK array and remote SESSION ID (part of the ACK array) */
157
+    overhead += ACK_SIZE(RELIABLE_ACK_SIZE);
158
+
159
+    /* Previous OpenVPN version calculated the maximum size and buffer of a
160
+     * control frame depending on the overhead of the data channel frame
161
+     * overhead and limited its maximum size to 1250. Since control frames
162
+     * also need to fit into data channel buffer we have the same
163
+     * default of 1500 + 100 as data channel buffers have. Increasing
164
+     * control channel mtu beyond this limit also increases the data channel
165
+     * buffers */
166
+    int tls_mtu = 1500;
167
+    frame->buf.payload_size = tls_mtu + 100;
168
+
169
+    frame->buf.headroom = overhead;
170
+    frame->buf.tailroom = overhead;
171
+
172
+    frame->tun_mtu = tls_mtu;
173
+
174
+}
175
+
176
+static void
177
+do_data_channel_round_trip(struct crypto_options *co)
178
+{
179
+    struct gc_arena gc = gc_new();
180
+
181
+    /* initialise frame for the test */
182
+    struct frame frame;
183
+    init_frame_parameters(&frame);
184
+
185
+    struct buffer src = alloc_buf_gc(frame.buf.payload_size, &gc);
186
+    struct buffer work = alloc_buf_gc(BUF_SIZE(&frame), &gc);
187
+    struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc);
188
+    struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc);
189
+    struct buffer buf = clear_buf();
190
+    void *buf_p;
191
+
192
+    /* init work */
193
+    ASSERT(buf_init(&work, frame.buf.headroom));
194
+
195
+    init_implicit_iv(co);
196
+    update_time();
197
+
198
+    /* Test encryption, decryption for all packet sizes */
199
+    for (int i = 1; i <= frame.buf.payload_size; ++i)
200
+    {
201
+
202
+        /* msg(M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i); */
203
+
204
+        /*
205
+         * Load src with random data.
206
+         */
207
+        ASSERT(buf_init(&src, 0));
208
+        ASSERT(i <= src.capacity);
209
+        src.len = i;
210
+        ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));
211
+
212
+        /* copy source to input buf */
213
+        buf = work;
214
+        buf_p = buf_write_alloc(&buf, BLEN(&src));
215
+        ASSERT(buf_p);
216
+        memcpy(buf_p, BPTR(&src), BLEN(&src));
217
+
218
+        /* initialize work buffer with buf.headroom bytes of prepend capacity */
219
+        ASSERT(buf_init(&encrypt_workspace, frame.buf.headroom));
220
+
221
+        /* encrypt */
222
+        openvpn_encrypt(&buf, encrypt_workspace, co);
223
+
224
+        /* decrypt */
225
+        openvpn_decrypt(&buf, decrypt_workspace, co, &frame, BPTR(&buf));
226
+
227
+        /* compare */
228
+        assert_int_equal(buf.len, src.len);
229
+        assert_memory_equal(BPTR(&src), BPTR(&buf), i);
230
+
231
+    }
232
+    gc_free(&gc);
233
+}
234
+
235
+
236
+
237
+struct crypto_options
238
+init_crypto_options(const char *cipher, const char *auth)
239
+{
240
+    struct key2 key2 = { .n = 2};
241
+
242
+    ASSERT(rand_bytes(key2.keys[0].cipher, sizeof(key2.keys[0].cipher)));
243
+    ASSERT(rand_bytes(key2.keys[0].hmac, sizeof(key2.keys[0].hmac)));
244
+    ASSERT(rand_bytes(key2.keys[1].cipher, sizeof(key2.keys[1].cipher)));
245
+    ASSERT(rand_bytes(key2.keys[1].hmac, sizeof(key2.keys)[1].hmac));
246
+
247
+    struct crypto_options co = { 0 };
248
+
249
+    struct key_type kt = create_kt(cipher, auth, "ssl-test");
250
+
251
+    init_key_ctx_bi(&co.key_ctx_bi, &key2, 0, &kt, "unit-test-ssl");
252
+    packet_id_init(&co.packet_id,  5, 5, "UNITTEST", 0);
253
+
254
+    return co;
255
+}
256
+
257
+static void
258
+uninit_crypto_options(struct crypto_options *co)
259
+{
260
+    packet_id_free(&co->packet_id);
261
+    free_key_ctx_bi(&co->key_ctx_bi);
262
+
263
+}
264
+
265
+
266
+static void
267
+run_data_channel_with_cipher(const char *cipher, const char *auth)
268
+{
269
+    struct crypto_options co = init_crypto_options(cipher, auth);
270
+    do_data_channel_round_trip(&co);
271
+    uninit_crypto_options(&co);
272
+}
273
+
274
+static void
275
+test_data_channel_roundtrip_aes_128_gcm(void **state)
276
+{
277
+    run_data_channel_with_cipher("AES-128-GCM", "none");
278
+}
279
+
280
+static void
281
+test_data_channel_roundtrip_aes_192_gcm(void **state)
282
+{
283
+    run_data_channel_with_cipher("AES-192-GCM", "none");
284
+}
285
+
286
+static void
287
+test_data_channel_roundtrip_aes_256_gcm(void **state)
288
+{
289
+    run_data_channel_with_cipher("AES-256-GCM", "none");
290
+}
291
+
292
+static void
293
+test_data_channel_roundtrip_aes_128_cbc(void **state)
294
+{
295
+    run_data_channel_with_cipher("AES-128-CBC", "SHA256");
296
+}
297
+
298
+static void
299
+test_data_channel_roundtrip_aes_192_cbc(void **state)
300
+{
301
+    run_data_channel_with_cipher("AES-192-CBC", "SHA256");
302
+}
303
+
304
+static void
305
+test_data_channel_roundtrip_aes_256_cbc(void **state)
306
+{
307
+    run_data_channel_with_cipher("AES-256-CBC", "SHA256");
308
+}
309
+
310
+static void
311
+test_data_channel_roundtrip_chacha20_poly1305(void **state)
312
+{
313
+    if (!cipher_valid("ChaCha20-Poly1305"))
314
+    {
315
+        skip();
316
+        return;
317
+    }
318
+    run_data_channel_with_cipher("ChaCha20-Poly1305", "none");
319
+}
320
+
321
+static void
322
+test_data_channel_roundtrip_bf_cbc(void **state)
323
+{
324
+    if (!cipher_valid("BF-CBC"))
325
+    {
326
+        skip();
327
+        return;
328
+    }
329
+    run_data_channel_with_cipher("BF-CBC", "SHA1");
330
+}
331
+
332
+
123 333
 int
124 334
 main(void)
125 335
 {
126 336
     openvpn_unit_test_setup();
127 337
 
128 338
     const struct CMUnitTest tests[] = {
129
-        cmocka_unit_test(crypto_pem_encode_certificate)
339
+        cmocka_unit_test(crypto_pem_encode_certificate),
340
+        cmocka_unit_test(test_data_channel_roundtrip_aes_128_gcm),
341
+        cmocka_unit_test(test_data_channel_roundtrip_aes_192_gcm),
342
+        cmocka_unit_test(test_data_channel_roundtrip_aes_256_gcm),
343
+        cmocka_unit_test(test_data_channel_roundtrip_chacha20_poly1305),
344
+        cmocka_unit_test(test_data_channel_roundtrip_aes_128_cbc),
345
+        cmocka_unit_test(test_data_channel_roundtrip_aes_192_cbc),
346
+        cmocka_unit_test(test_data_channel_roundtrip_aes_256_cbc),
347
+        cmocka_unit_test(test_data_channel_roundtrip_bf_cbc),
130 348
     };
131 349
 
132 350
 #if defined(ENABLE_CRYPTO_OPENSSL)
133 351
     tls_init_lib();
134 352
 #endif
135 353
 
136
-    int ret = cmocka_run_group_tests_name("crypto tests", tests, NULL, NULL);
354
+    int ret = cmocka_run_group_tests_name("ssl tests", tests, NULL, NULL);
137 355
 
138 356
 #if defined(ENABLE_CRYPTO_OPENSSL)
139 357
     tls_free_lib();