From 1079962e4c06f88a54e50d997c1b7e84303d30b4 Mon Sep 17 00:00:00 2001 From: Bernhard Schmidt Date: Sat, 15 Aug 2020 21:29:50 +0200 Subject: New upstream version 2.5~beta1 --- tests/unit_tests/openvpn/test_tls_crypt.c | 452 +++++++++++++++++++++++++++--- 1 file changed, 416 insertions(+), 36 deletions(-) (limited to 'tests/unit_tests/openvpn/test_tls_crypt.c') diff --git a/tests/unit_tests/openvpn/test_tls_crypt.c b/tests/unit_tests/openvpn/test_tls_crypt.c index f5618f8..218772e 100644 --- a/tests/unit_tests/openvpn/test_tls_crypt.c +++ b/tests/unit_tests/openvpn/test_tls_crypt.c @@ -27,8 +27,6 @@ #include "config-msvc.h" #endif -#ifdef ENABLE_CRYPTO - #include "syshead.h" #include @@ -45,9 +43,98 @@ #define TESTBUF_SIZE 128 -const char plaintext_short[1]; +/* Defines for use in the tests and the mock parse_line() */ +#define PATH1 "/s p a c e" +#define PATH2 "/foo bar/baz" +#define PARAM1 "param1" +#define PARAM2 "param two" + +static const char *test_server_key = \ + "-----BEGIN OpenVPN tls-crypt-v2 server key-----\n" + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v\n" + "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f\n" + "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=\n" + "-----END OpenVPN tls-crypt-v2 server key-----\n"; + +static const char *test_client_key = \ + "-----BEGIN OpenVPN tls-crypt-v2 client key-----\n" + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v\n" + "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f\n" + "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P\n" + "kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/\n" + "wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v\n" + "8PHy8/T19vf4+fr7/P3+/xd9pcB0qUYZsWvkrLcfGmzPJPM8a7r0mEWdXwbDadSV\n" + "LHg5bv2TwlmPR3HgaMr8o9LTh9hxUTkrH3S0PfKRNwcso86ua/dBFTyXsM9tg4aw\n" + "3dS6ogH9AkaT+kRRDgNcKWkQCbwmJK2JlfkXHBwbAtmn78AkNuho6QCFqCdqGab3\n" + "zh2vheFqGMPdGpukbFrT3rcO3VLxUeG+RdzXiMTCpJSovFBP1lDkYwYJPnz6daEh\n" + "j0TzJ3BVru9W3CpotdNt7u09knxAfpCxjtrP3semsDew/gTBtcfQ/OoTFyFHnN5k\n" + "RZ+q17SC4nba3Pp8/Fs0+hSbv2tJozoD8SElFq7SIWJsciTYh8q8f5yQxjdt4Wxu\n" + "/Z5wtPCAZ0tOzj4ItTI77fBOYRTfEayzHgEr\n" + "-----END OpenVPN tls-crypt-v2 client key-----\n"; + + +/* Has custom metadata of AABBCCDD (base64) */ +static const char *test_client_key_metadata = \ + "-----BEGIN OpenVPN tls-crypt-v2 client key-----\n" + "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4v\n" + "MDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5f\n" + "YGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P\n" + "kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/\n" + "wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v\n" + "8PHy8/T19vf4+fr7/P3+/2ntp1WCqhcLjJQY/igkjNt3Yb6i0neqFkfrOp2UCDcz\n" + "6RSJtPLZbvOOKUHk2qwxPYUsFCnz/IWV6/ZiLRrabzUpS8oSN1HS6P7qqAdrHKgf\n" + "hVTHasdSf2UdMTPC7HBgnP9Ll0FhKN0h7vSzbbt7QM7wH9mr1ecc/Mt0SYW2lpwA\n" + "aJObYGTyk6hTgWm0g/MLrworLrezTqUHBZzVsu+LDyqLWK1lzJNd66MuNOsGA4YF\n" + "fbCsDh8n3H+Cw1k5YNBZDYYJOtVUgBWXheO6vgoOmqDdI0dAQ3hVo9DE+SkCFjgf\n" + "l4FY2yLEh9ZVZZrl1eD1Owh/X178CkHrBJYl9LNQSyQEKlDGWwBLQ/pY3qtjctr3\n" + "pV62MPQdBo+1lcsjDCJVQA6XUyltas4BKQ==\n" + "-----END OpenVPN tls-crypt-v2 client key-----\n"; + +int +__wrap_parse_line(const char *line, char **p, const int n, const char *file, + const int line_num, int msglevel, struct gc_arena *gc) +{ + p[0] = PATH1 PATH2; + p[1] = PARAM1; + p[2] = PARAM2; + return 3; +} + +bool +__wrap_buffer_write_file(const char *filename, const struct buffer *buf) +{ + const char *pem = BSTR(buf); + check_expected(filename); + check_expected(pem); + + return mock(); +} + +struct buffer +__wrap_buffer_read_from_file(const char *filename, struct gc_arena *gc) +{ + check_expected(filename); -struct test_context { + const char *pem_str = (const char *) mock(); + struct buffer ret = alloc_buf_gc(strlen(pem_str) + 1, gc); + buf_write(&ret, pem_str, strlen(pem_str) + 1); + + return ret; +} + + +/** Predictable random for tests */ +int +__wrap_rand_bytes(uint8_t *output, int len) +{ + for (int i = 0; i < len; i++) + { + output[i] = i; + } + return true; +} + +struct test_tls_crypt_context { struct crypto_options co; struct key_type kt; struct buffer source; @@ -56,8 +143,9 @@ struct test_context { }; static int -setup(void **state) { - struct test_context *ctx = calloc(1, sizeof(*ctx)); +test_tls_crypt_setup(void **state) +{ + struct test_tls_crypt_context *ctx = calloc(1, sizeof(*ctx)); *state = ctx; struct key key = { 0 }; @@ -77,17 +165,21 @@ setup(void **state) { ctx->unwrapped = alloc_buf(TESTBUF_SIZE); /* Write test plaintext */ - buf_write(&ctx->source, plaintext_short, sizeof(plaintext_short)); + const char *plaintext = "1234567890"; + buf_write(&ctx->source, plaintext, strlen(plaintext)); - /* Write dummy opcode and session id */ - buf_write(&ctx->ciphertext, "012345678", 1 + 8); + /* Write test ciphertext */ + const char *ciphertext = "012345678"; + buf_write(&ctx->ciphertext, ciphertext, strlen(ciphertext)); return 0; } static int -teardown(void **state) { - struct test_context *ctx = (struct test_context *) *state; +test_tls_crypt_teardown(void **state) +{ + struct test_tls_crypt_context *ctx = + (struct test_tls_crypt_context *)*state; free_buf(&ctx->source); free_buf(&ctx->ciphertext); @@ -100,7 +192,8 @@ teardown(void **state) { return 0; } -static void skip_if_tls_crypt_not_supported(struct test_context *ctx) +static void +skip_if_tls_crypt_not_supported(struct test_tls_crypt_context *ctx) { if (!ctx->kt.cipher || !ctx->kt.digest) { @@ -112,8 +205,9 @@ static void skip_if_tls_crypt_not_supported(struct test_context *ctx) * Check that short messages are successfully wrapped-and-unwrapped. */ static void -tls_crypt_loopback(void **state) { - struct test_context *ctx = (struct test_context *) *state; +tls_crypt_loopback(void **state) +{ + struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state; skip_if_tls_crypt_not_supported(ctx); @@ -129,8 +223,9 @@ tls_crypt_loopback(void **state) { * Check that zero-byte messages are successfully wrapped-and-unwrapped. */ static void -tls_crypt_loopback_zero_len(void **state) { - struct test_context *ctx = (struct test_context *) *state; +tls_crypt_loopback_zero_len(void **state) +{ + struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state; skip_if_tls_crypt_not_supported(ctx); @@ -148,8 +243,9 @@ tls_crypt_loopback_zero_len(void **state) { * Check that max-length messages are successfully wrapped-and-unwrapped. */ static void -tls_crypt_loopback_max_len(void **state) { - struct test_context *ctx = (struct test_context *) *state; +tls_crypt_loopback_max_len(void **state) +{ + struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state; skip_if_tls_crypt_not_supported(ctx); @@ -169,8 +265,9 @@ tls_crypt_loopback_max_len(void **state) { * Check that too-long messages are gracefully rejected. */ static void -tls_crypt_fail_msg_too_long(void **state) { - struct test_context *ctx = (struct test_context *) *state; +tls_crypt_fail_msg_too_long(void **state) +{ + struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state; skip_if_tls_crypt_not_supported(ctx); @@ -185,8 +282,9 @@ tls_crypt_fail_msg_too_long(void **state) { * are not accepted. */ static void -tls_crypt_fail_invalid_key(void **state) { - struct test_context *ctx = (struct test_context *) *state; +tls_crypt_fail_invalid_key(void **state) +{ + struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state; skip_if_tls_crypt_not_supported(ctx); @@ -204,8 +302,9 @@ tls_crypt_fail_invalid_key(void **state) { * Check that replayed packets are not accepted. */ static void -tls_crypt_fail_replay(void **state) { - struct test_context *ctx = (struct test_context *) *state; +tls_crypt_fail_replay(void **state) +{ + struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state; skip_if_tls_crypt_not_supported(ctx); @@ -223,8 +322,9 @@ tls_crypt_fail_replay(void **state) { * know the packet ID yet. */ static void -tls_crypt_ignore_replay(void **state) { - struct test_context *ctx = (struct test_context *) *state; +tls_crypt_ignore_replay(void **state) +{ + struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state; skip_if_tls_crypt_not_supported(ctx); @@ -238,22 +338,304 @@ tls_crypt_ignore_replay(void **state) { assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co)); } +struct test_tls_crypt_v2_context { + struct gc_arena gc; + struct key2 server_key2; + struct key_ctx_bi server_keys; + struct key2 client_key2; + struct key_ctx_bi client_key; + struct buffer metadata; + struct buffer unwrapped_metadata; + struct buffer wkc; +}; + +static int +test_tls_crypt_v2_setup(void **state) +{ + struct test_tls_crypt_v2_context *ctx = calloc(1, sizeof(*ctx)); + *state = ctx; + + ctx->gc = gc_new(); + + /* Slightly longer buffers to be able to test too-long data */ + ctx->metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN+16, &ctx->gc); + ctx->unwrapped_metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN+16, + &ctx->gc); + ctx->wkc = alloc_buf_gc(TLS_CRYPT_V2_MAX_WKC_LEN+16, &ctx->gc); + + /* Generate server key */ + rand_bytes((void *)ctx->server_key2.keys, sizeof(ctx->server_key2.keys)); + ctx->server_key2.n = 2; + struct key_type kt = tls_crypt_kt(); + init_key_ctx_bi(&ctx->server_keys, &ctx->server_key2, + KEY_DIRECTION_BIDIRECTIONAL, &kt, + "tls-crypt-v2 server key"); + + /* Generate client key */ + rand_bytes((void *)ctx->client_key2.keys, sizeof(ctx->client_key2.keys)); + ctx->client_key2.n = 2; + + return 0; +} + +static int +test_tls_crypt_v2_teardown(void **state) +{ + struct test_tls_crypt_v2_context *ctx = + (struct test_tls_crypt_v2_context *) *state; + + free_key_ctx_bi(&ctx->server_keys); + free_key_ctx_bi(&ctx->client_key); + + gc_free(&ctx->gc); + + free(ctx); + + return 0; +} + +/** + * Check wrapping and unwrapping a tls-crypt-v2 client key without metadata. + */ +static void +tls_crypt_v2_wrap_unwrap_no_metadata(void **state) +{ + struct test_tls_crypt_v2_context *ctx = + (struct test_tls_crypt_v2_context *) *state; + + struct buffer wrapped_client_key = alloc_buf_gc(TLS_CRYPT_V2_MAX_WKC_LEN, + &ctx->gc); + assert_true(tls_crypt_v2_wrap_client_key(&wrapped_client_key, + &ctx->client_key2, + &ctx->metadata, + &ctx->server_keys.encrypt, + &ctx->gc)); + + struct buffer unwrap_metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, + &ctx->gc); + struct key2 unwrapped_client_key2 = { 0 }; + assert_true(tls_crypt_v2_unwrap_client_key(&unwrapped_client_key2, + &unwrap_metadata, + wrapped_client_key, + &ctx->server_keys.decrypt)); + + assert_true(0 == memcmp(ctx->client_key2.keys, unwrapped_client_key2.keys, + sizeof(ctx->client_key2.keys))); +} + +/** + * Check wrapping and unwrapping a tls-crypt-v2 client key with maximum length + * metadata. + */ +static void +tls_crypt_v2_wrap_unwrap_max_metadata(void **state) +{ + struct test_tls_crypt_v2_context *ctx = + (struct test_tls_crypt_v2_context *) *state; + + uint8_t *metadata = + buf_write_alloc(&ctx->metadata, TLS_CRYPT_V2_MAX_METADATA_LEN); + assert_true(rand_bytes(metadata, TLS_CRYPT_V2_MAX_METADATA_LEN)); + assert_true(tls_crypt_v2_wrap_client_key(&ctx->wkc, &ctx->client_key2, + &ctx->metadata, + &ctx->server_keys.encrypt, + &ctx->gc)); + + struct buffer unwrap_metadata = alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN, + &ctx->gc); + struct key2 unwrapped_client_key2 = { 0 }; + assert_true(tls_crypt_v2_unwrap_client_key(&unwrapped_client_key2, + &unwrap_metadata, ctx->wkc, + &ctx->server_keys.decrypt)); + + assert_true(0 == memcmp(ctx->client_key2.keys, unwrapped_client_key2.keys, + sizeof(ctx->client_key2.keys))); + assert_true(buf_equal(&ctx->metadata, &unwrap_metadata)); + + struct tls_wrap_ctx wrap_ctx = { + .mode = TLS_WRAP_CRYPT, + .tls_crypt_v2_server_key = ctx->server_keys.encrypt, + }; + assert_true(tls_crypt_v2_extract_client_key(&ctx->wkc, &wrap_ctx, NULL)); + tls_wrap_free(&wrap_ctx); +} + +/** + * Check that wrapping a tls-crypt-v2 client key with too long metadata fails + * as expected. + */ +static void +tls_crypt_v2_wrap_too_long_metadata(void **state) +{ + struct test_tls_crypt_v2_context *ctx = + (struct test_tls_crypt_v2_context *) *state; + + assert_true(buf_inc_len(&ctx->metadata, TLS_CRYPT_V2_MAX_METADATA_LEN+1)); + assert_false(tls_crypt_v2_wrap_client_key(&ctx->wkc, &ctx->client_key2, + &ctx->metadata, + &ctx->server_keys.encrypt, + &ctx->gc)); +} + +/** + * Check that unwrapping a tls-crypt-v2 client key with the wrong server key + * fails as expected. + */ +static void +tls_crypt_v2_wrap_unwrap_wrong_key(void **state) +{ + struct test_tls_crypt_v2_context *ctx = + (struct test_tls_crypt_v2_context *) *state; + + assert_true(tls_crypt_v2_wrap_client_key(&ctx->wkc, &ctx->client_key2, + &ctx->metadata, + &ctx->server_keys.encrypt, + &ctx->gc)); + + /* Change server key */ + struct key_type kt = tls_crypt_kt(); + free_key_ctx_bi(&ctx->server_keys); + memset(&ctx->server_key2.keys, 0, sizeof(ctx->server_key2.keys)); + init_key_ctx_bi(&ctx->server_keys, &ctx->server_key2, + KEY_DIRECTION_BIDIRECTIONAL, &kt, + "wrong tls-crypt-v2 server key"); + + + struct key2 unwrapped_client_key2 = { 0 }; + assert_false(tls_crypt_v2_unwrap_client_key(&unwrapped_client_key2, + &ctx->unwrapped_metadata, + ctx->wkc, + &ctx->server_keys.decrypt)); + + const struct key2 zero = { 0 }; + assert_true(0 == memcmp(&unwrapped_client_key2, &zero, sizeof(zero))); + assert_true(0 == BLEN(&ctx->unwrapped_metadata)); +} + +/** + * Check that unwrapping a tls-crypt-v2 client key to a too small metadata + * buffer fails as expected. + */ +static void +tls_crypt_v2_wrap_unwrap_dst_too_small(void **state) +{ + struct test_tls_crypt_v2_context *ctx = + (struct test_tls_crypt_v2_context *) *state; + + uint8_t *metadata = + buf_write_alloc(&ctx->metadata, TLS_CRYPT_V2_MAX_METADATA_LEN); + assert_true(rand_bytes(metadata, TLS_CRYPT_V2_MAX_METADATA_LEN)); + assert_true(tls_crypt_v2_wrap_client_key(&ctx->wkc, &ctx->client_key2, + &ctx->metadata, + &ctx->server_keys.encrypt, + &ctx->gc)); + + struct key2 unwrapped_client_key2 = { 0 }; + struct buffer unwrapped_metadata = + alloc_buf_gc(TLS_CRYPT_V2_MAX_METADATA_LEN-1, &ctx->gc); + assert_false(tls_crypt_v2_unwrap_client_key(&unwrapped_client_key2, + &unwrapped_metadata, ctx->wkc, + &ctx->server_keys.decrypt)); + + const struct key2 zero = { 0 }; + assert_true(0 == memcmp(&unwrapped_client_key2, &zero, sizeof(zero))); + assert_true(0 == BLEN(&ctx->unwrapped_metadata)); +} + +static void +test_tls_crypt_v2_write_server_key_file(void **state) +{ + const char *filename = "testfilename.key"; + + expect_string(__wrap_buffer_write_file, filename, filename); + expect_memory(__wrap_buffer_write_file, pem, test_server_key, + strlen(test_server_key)); + will_return(__wrap_buffer_write_file, true); + + tls_crypt_v2_write_server_key_file(filename); +} + +static void +test_tls_crypt_v2_write_client_key_file(void **state) +{ + const char *filename = "testfilename.key"; + + /* Test writing the client key */ + expect_string(__wrap_buffer_write_file, filename, filename); + expect_memory(__wrap_buffer_write_file, pem, test_client_key, + strlen(test_client_key)); + will_return(__wrap_buffer_write_file, true); + + /* Key generation re-reads the created file as a sanity check */ + expect_string(__wrap_buffer_read_from_file, filename, filename); + will_return(__wrap_buffer_read_from_file, test_client_key); + + tls_crypt_v2_write_client_key_file(filename, NULL, test_server_key, true); +} + +static void +test_tls_crypt_v2_write_client_key_file_metadata(void **state) +{ + const char *filename = "testfilename.key"; + const char *b64metadata = "AABBCCDD"; + + /* Test writing the client key */ + expect_string(__wrap_buffer_write_file, filename, filename); + expect_memory(__wrap_buffer_write_file, pem, test_client_key_metadata, + strlen(test_client_key_metadata)); + will_return(__wrap_buffer_write_file, true); + + /* Key generation re-reads the created file as a sanity check */ + expect_string(__wrap_buffer_read_from_file, filename, filename); + will_return(__wrap_buffer_read_from_file, test_client_key_metadata); + + tls_crypt_v2_write_client_key_file(filename, b64metadata, test_server_key, + true); +} + int -main(void) { +main(void) +{ const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(tls_crypt_loopback, setup, teardown), + cmocka_unit_test_setup_teardown(tls_crypt_loopback, + test_tls_crypt_setup, + test_tls_crypt_teardown), cmocka_unit_test_setup_teardown(tls_crypt_loopback_zero_len, - setup, teardown), + test_tls_crypt_setup, + test_tls_crypt_teardown), cmocka_unit_test_setup_teardown(tls_crypt_loopback_max_len, - setup, teardown), + test_tls_crypt_setup, + test_tls_crypt_teardown), cmocka_unit_test_setup_teardown(tls_crypt_fail_msg_too_long, - setup, teardown), + test_tls_crypt_setup, + test_tls_crypt_teardown), cmocka_unit_test_setup_teardown(tls_crypt_fail_invalid_key, - setup, teardown), + test_tls_crypt_setup, + test_tls_crypt_teardown), cmocka_unit_test_setup_teardown(tls_crypt_fail_replay, - setup, teardown), + test_tls_crypt_setup, + test_tls_crypt_teardown), cmocka_unit_test_setup_teardown(tls_crypt_ignore_replay, - setup, teardown), + test_tls_crypt_setup, + test_tls_crypt_teardown), + cmocka_unit_test_setup_teardown(tls_crypt_v2_wrap_unwrap_no_metadata, + test_tls_crypt_v2_setup, + test_tls_crypt_v2_teardown), + cmocka_unit_test_setup_teardown(tls_crypt_v2_wrap_unwrap_max_metadata, + test_tls_crypt_v2_setup, + test_tls_crypt_v2_teardown), + cmocka_unit_test_setup_teardown(tls_crypt_v2_wrap_too_long_metadata, + test_tls_crypt_v2_setup, + test_tls_crypt_v2_teardown), + cmocka_unit_test_setup_teardown(tls_crypt_v2_wrap_unwrap_wrong_key, + test_tls_crypt_v2_setup, + test_tls_crypt_v2_teardown), + cmocka_unit_test_setup_teardown(tls_crypt_v2_wrap_unwrap_dst_too_small, + test_tls_crypt_v2_setup, + test_tls_crypt_v2_teardown), + cmocka_unit_test(test_tls_crypt_v2_write_server_key_file), + cmocka_unit_test(test_tls_crypt_v2_write_client_key_file), + cmocka_unit_test(test_tls_crypt_v2_write_client_key_file_metadata), }; #if defined(ENABLE_CRYPTO_OPENSSL) @@ -268,5 +650,3 @@ main(void) { return ret; } - -#endif /* ENABLE_CRYPTO */ -- cgit v1.2.3