Skip to content

Commit

Permalink
Add unit test for encrypting/decrypting data channel
Browse files Browse the repository at this point in the history
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 <[email protected]>
Message-Id: <[email protected]>
URL: https://www.mail-archive.com/[email protected]/msg28195.html
Signed-off-by: Gert Doering <[email protected]>
  • Loading branch information
schwabe authored and cron2 committed Feb 8, 2024
1 parent ca122f9 commit 70b39f2
Showing 1 changed file with 223 additions and 2 deletions.
225 changes: 223 additions & 2 deletions tests/unit_tests/openvpn/test_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
#include "ssl_verify_backend.h"
#include "win32.h"
#include "test_common.h"
#include "ssl.h"
#include "buffer.h"
#include "packet_id.h"

/* Mock function to be allowed to include win32.c which is required for
* getting the temp directory */
Expand Down Expand Up @@ -120,20 +123,238 @@ crypto_pem_encode_certificate(void **state)
gc_free(&gc);
}

static void
init_implicit_iv(struct crypto_options *co)
{
cipher_ctx_t *cipher = co->key_ctx_bi.encrypt.cipher;

if (cipher_ctx_mode_aead(cipher))
{
size_t impl_iv_len = cipher_ctx_iv_length(cipher) - sizeof(packet_id_type);
ASSERT(cipher_ctx_iv_length(cipher) <= OPENVPN_MAX_IV_LENGTH);
ASSERT(cipher_ctx_iv_length(cipher) >= OPENVPN_AEAD_MIN_IV_LEN);

/* Generate dummy implicit IV */
ASSERT(rand_bytes(co->key_ctx_bi.encrypt.implicit_iv,
OPENVPN_MAX_IV_LENGTH));
co->key_ctx_bi.encrypt.implicit_iv_len = impl_iv_len;

memcpy(co->key_ctx_bi.decrypt.implicit_iv,
co->key_ctx_bi.encrypt.implicit_iv, OPENVPN_MAX_IV_LENGTH);
co->key_ctx_bi.decrypt.implicit_iv_len = impl_iv_len;
}
}

static void
init_frame_parameters(struct frame *frame)
{
int overhead = 0;

/* tls-auth and tls-crypt */
overhead += 128;

/* TCP length field and opcode */
overhead += 3;

/* ACK array and remote SESSION ID (part of the ACK array) */
overhead += ACK_SIZE(RELIABLE_ACK_SIZE);

/* Previous OpenVPN version calculated the maximum size and buffer of a
* control frame depending on the overhead of the data channel frame
* overhead and limited its maximum size to 1250. Since control frames
* also need to fit into data channel buffer we have the same
* default of 1500 + 100 as data channel buffers have. Increasing
* control channel mtu beyond this limit also increases the data channel
* buffers */
int tls_mtu = 1500;
frame->buf.payload_size = tls_mtu + 100;

frame->buf.headroom = overhead;
frame->buf.tailroom = overhead;

frame->tun_mtu = tls_mtu;

}

static void
do_data_channel_round_trip(struct crypto_options *co)
{
struct gc_arena gc = gc_new();

/* initialise frame for the test */
struct frame frame;
init_frame_parameters(&frame);

struct buffer src = alloc_buf_gc(frame.buf.payload_size, &gc);
struct buffer work = alloc_buf_gc(BUF_SIZE(&frame), &gc);
struct buffer encrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc);
struct buffer decrypt_workspace = alloc_buf_gc(BUF_SIZE(&frame), &gc);
struct buffer buf = clear_buf();
void *buf_p;

/* init work */
ASSERT(buf_init(&work, frame.buf.headroom));

init_implicit_iv(co);
update_time();

/* Test encryption, decryption for all packet sizes */
for (int i = 1; i <= frame.buf.payload_size; ++i)
{

/* msg(M_INFO, "TESTING ENCRYPT/DECRYPT of packet length=%d", i); */

/*
* Load src with random data.
*/
ASSERT(buf_init(&src, 0));
ASSERT(i <= src.capacity);
src.len = i;
ASSERT(rand_bytes(BPTR(&src), BLEN(&src)));

/* copy source to input buf */
buf = work;
buf_p = buf_write_alloc(&buf, BLEN(&src));
ASSERT(buf_p);
memcpy(buf_p, BPTR(&src), BLEN(&src));

/* initialize work buffer with buf.headroom bytes of prepend capacity */
ASSERT(buf_init(&encrypt_workspace, frame.buf.headroom));

/* encrypt */
openvpn_encrypt(&buf, encrypt_workspace, co);

/* decrypt */
openvpn_decrypt(&buf, decrypt_workspace, co, &frame, BPTR(&buf));

/* compare */
assert_int_equal(buf.len, src.len);
assert_memory_equal(BPTR(&src), BPTR(&buf), i);

}
gc_free(&gc);
}



struct crypto_options
init_crypto_options(const char *cipher, const char *auth)
{
struct key2 key2 = { .n = 2};

ASSERT(rand_bytes(key2.keys[0].cipher, sizeof(key2.keys[0].cipher)));
ASSERT(rand_bytes(key2.keys[0].hmac, sizeof(key2.keys[0].hmac)));
ASSERT(rand_bytes(key2.keys[1].cipher, sizeof(key2.keys[1].cipher)));
ASSERT(rand_bytes(key2.keys[1].hmac, sizeof(key2.keys)[1].hmac));

struct crypto_options co = { 0 };

struct key_type kt = create_kt(cipher, auth, "ssl-test");

init_key_ctx_bi(&co.key_ctx_bi, &key2, 0, &kt, "unit-test-ssl");
packet_id_init(&co.packet_id, 5, 5, "UNITTEST", 0);

return co;
}

static void
uninit_crypto_options(struct crypto_options *co)
{
packet_id_free(&co->packet_id);
free_key_ctx_bi(&co->key_ctx_bi);

}


static void
run_data_channel_with_cipher(const char *cipher, const char *auth)
{
struct crypto_options co = init_crypto_options(cipher, auth);
do_data_channel_round_trip(&co);
uninit_crypto_options(&co);
}

static void
test_data_channel_roundtrip_aes_128_gcm(void **state)
{
run_data_channel_with_cipher("AES-128-GCM", "none");
}

static void
test_data_channel_roundtrip_aes_192_gcm(void **state)
{
run_data_channel_with_cipher("AES-192-GCM", "none");
}

static void
test_data_channel_roundtrip_aes_256_gcm(void **state)
{
run_data_channel_with_cipher("AES-256-GCM", "none");
}

static void
test_data_channel_roundtrip_aes_128_cbc(void **state)
{
run_data_channel_with_cipher("AES-128-CBC", "SHA256");
}

static void
test_data_channel_roundtrip_aes_192_cbc(void **state)
{
run_data_channel_with_cipher("AES-192-CBC", "SHA256");
}

static void
test_data_channel_roundtrip_aes_256_cbc(void **state)
{
run_data_channel_with_cipher("AES-256-CBC", "SHA256");
}

static void
test_data_channel_roundtrip_chacha20_poly1305(void **state)
{
if (!cipher_valid("ChaCha20-Poly1305"))
{
skip();
return;
}
run_data_channel_with_cipher("ChaCha20-Poly1305", "none");
}

static void
test_data_channel_roundtrip_bf_cbc(void **state)
{
if (!cipher_valid("BF-CBC"))
{
skip();
return;
}
run_data_channel_with_cipher("BF-CBC", "SHA1");
}


int
main(void)
{
openvpn_unit_test_setup();

const struct CMUnitTest tests[] = {
cmocka_unit_test(crypto_pem_encode_certificate)
cmocka_unit_test(crypto_pem_encode_certificate),
cmocka_unit_test(test_data_channel_roundtrip_aes_128_gcm),
cmocka_unit_test(test_data_channel_roundtrip_aes_192_gcm),
cmocka_unit_test(test_data_channel_roundtrip_aes_256_gcm),
cmocka_unit_test(test_data_channel_roundtrip_chacha20_poly1305),
cmocka_unit_test(test_data_channel_roundtrip_aes_128_cbc),
cmocka_unit_test(test_data_channel_roundtrip_aes_192_cbc),
cmocka_unit_test(test_data_channel_roundtrip_aes_256_cbc),
cmocka_unit_test(test_data_channel_roundtrip_bf_cbc),
};

#if defined(ENABLE_CRYPTO_OPENSSL)
tls_init_lib();
#endif

int ret = cmocka_run_group_tests_name("crypto tests", tests, NULL, NULL);
int ret = cmocka_run_group_tests_name("ssl tests", tests, NULL, NULL);

#if defined(ENABLE_CRYPTO_OPENSSL)
tls_free_lib();
Expand Down

0 comments on commit 70b39f2

Please sign in to comment.