tests/unit_tests/openvpn/test_tls_crypt.c
3b185161
 /*
  *  OpenVPN -- An application to securely tunnel IP networks
  *             over a single UDP port, with support for SSL/TLS-based
  *             session authentication and key exchange,
  *             packet encryption, packet authentication, and
  *             packet compression.
  *
49979459
  *  Copyright (C) 2016-2018 Fox Crypto B.V. <openvpn@fox-it.com>
3b185161
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2
  *  as published by the Free Software Foundation.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
caa54ac3
  *  You should have received a copy of the GNU General Public License along
  *  with this program; if not, write to the Free Software Foundation, Inc.,
  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
3b185161
  */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #elif defined(_MSC_VER)
 #include "config-msvc.h"
 #endif
 
 #include "syshead.h"
 
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <string.h>
 #include <setjmp.h>
 #include <cmocka.h>
 
489c7bf9
 #include "tls_crypt.c"
3b185161
 
 #include "mock_msg.h"
 
81d882d5
 #define TESTBUF_SIZE            128
3b185161
 
 const char plaintext_short[1];
 
a98a5676
 struct test_tls_crypt_context {
81d882d5
     struct crypto_options co;
     struct key_type kt;
     struct buffer source;
     struct buffer ciphertext;
     struct buffer unwrapped;
3b185161
 };
 
81d882d5
 static int
a98a5676
 test_tls_crypt_setup(void **state) {
     struct test_tls_crypt_context *ctx = calloc(1, sizeof(*ctx));
534c8f24
     *state = ctx;
3b185161
 
489c7bf9
     struct key key = { 0 };
 
     ctx->kt = tls_crypt_kt();
     if (!ctx->kt.cipher || !ctx->kt.digest)
534c8f24
     {
         return 0;
     }
81d882d5
     init_key_ctx(&ctx->co.key_ctx_bi.encrypt, &key, &ctx->kt, true, "TEST");
     init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
3b185161
 
81d882d5
     packet_id_init(&ctx->co.packet_id, 0, 0, "test", 0);
3b185161
 
     ctx->source = alloc_buf(TESTBUF_SIZE);
     ctx->ciphertext = alloc_buf(TESTBUF_SIZE);
     ctx->unwrapped = alloc_buf(TESTBUF_SIZE);
 
     /* Write test plaintext */
     buf_write(&ctx->source, plaintext_short, sizeof(plaintext_short));
 
     /* Write dummy opcode and session id */
     buf_write(&ctx->ciphertext, "012345678", 1 + 8);
 
     return 0;
 }
 
81d882d5
 static int
a98a5676
 test_tls_crypt_teardown(void **state) {
     struct test_tls_crypt_context *ctx =
             (struct test_tls_crypt_context *)*state;
3b185161
 
81d882d5
     free_buf(&ctx->source);
     free_buf(&ctx->ciphertext);
     free_buf(&ctx->unwrapped);
3b185161
 
81d882d5
     free_key_ctx_bi(&ctx->co.key_ctx_bi);
3b185161
 
     free(ctx);
 
     return 0;
 }
 
a98a5676
 static void skip_if_tls_crypt_not_supported(struct test_tls_crypt_context *ctx)
534c8f24
 {
     if (!ctx->kt.cipher || !ctx->kt.digest)
     {
         skip();
     }
 }
 
3b185161
 /**
  * Check that short messages are successfully wrapped-and-unwrapped.
  */
81d882d5
 static void
 tls_crypt_loopback(void **state) {
a98a5676
     struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state;
81d882d5
 
534c8f24
     skip_if_tls_crypt_not_supported(ctx);
 
81d882d5
     assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co));
     assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
     assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
     assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped));
     assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped),
                         BLEN(&ctx->source));
3b185161
 }
 
 /**
  * Check that zero-byte messages are successfully wrapped-and-unwrapped.
  */
81d882d5
 static void
 tls_crypt_loopback_zero_len(void **state) {
a98a5676
     struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state;
3b185161
 
534c8f24
     skip_if_tls_crypt_not_supported(ctx);
 
81d882d5
     buf_clear(&ctx->source);
3b185161
 
81d882d5
     assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co));
     assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
     assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
     assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped));
     assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped),
                         BLEN(&ctx->source));
3b185161
 }
 
 /**
  * Check that max-length messages are successfully wrapped-and-unwrapped.
  */
81d882d5
 static void
 tls_crypt_loopback_max_len(void **state) {
a98a5676
     struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state;
81d882d5
 
534c8f24
     skip_if_tls_crypt_not_supported(ctx);
 
81d882d5
     buf_clear(&ctx->source);
     assert_non_null(buf_write_alloc(&ctx->source,
                                     TESTBUF_SIZE - BLEN(&ctx->ciphertext) - tls_crypt_buf_overhead()));
 
     assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co));
     assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
     assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
     assert_int_equal(BLEN(&ctx->source), BLEN(&ctx->unwrapped));
     assert_memory_equal(BPTR(&ctx->source), BPTR(&ctx->unwrapped),
                         BLEN(&ctx->source));
3b185161
 }
 
 /**
  * Check that too-long messages are gracefully rejected.
  */
81d882d5
 static void
 tls_crypt_fail_msg_too_long(void **state) {
a98a5676
     struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state;
3b185161
 
534c8f24
     skip_if_tls_crypt_not_supported(ctx);
 
81d882d5
     buf_clear(&ctx->source);
     assert_non_null(buf_write_alloc(&ctx->source,
                                     TESTBUF_SIZE - BLEN(&ctx->ciphertext) - tls_crypt_buf_overhead() + 1));
     assert_false(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co));
3b185161
 }
 
 /**
  * Check that packets that were wrapped (or unwrapped) with a different key
  * are not accepted.
  */
81d882d5
 static void
 tls_crypt_fail_invalid_key(void **state) {
a98a5676
     struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state;
3b185161
 
534c8f24
     skip_if_tls_crypt_not_supported(ctx);
 
81d882d5
     /* Change decrypt key */
     struct key key = { { 1 } };
     free_key_ctx(&ctx->co.key_ctx_bi.decrypt);
     init_key_ctx(&ctx->co.key_ctx_bi.decrypt, &key, &ctx->kt, false, "TEST");
3b185161
 
81d882d5
     assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co));
     assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
     assert_false(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
3b185161
 }
 
 /**
  * Check that replayed packets are not accepted.
  */
81d882d5
 static void
 tls_crypt_fail_replay(void **state) {
a98a5676
     struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state;
81d882d5
 
534c8f24
     skip_if_tls_crypt_not_supported(ctx);
 
81d882d5
     assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co));
     assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
     struct buffer tmp = ctx->ciphertext;
     assert_true(tls_crypt_unwrap(&tmp, &ctx->unwrapped, &ctx->co));
     buf_clear(&ctx->unwrapped);
     assert_false(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
3b185161
 }
 
 /**
  * Check that packet replays are accepted when CO_IGNORE_PACKET_ID is set. This
  * is used for the first control channel packet that arrives, because we don't
  * know the packet ID yet.
  */
81d882d5
 static void
 tls_crypt_ignore_replay(void **state) {
a98a5676
     struct test_tls_crypt_context *ctx = (struct test_tls_crypt_context *) *state;
3b185161
 
534c8f24
     skip_if_tls_crypt_not_supported(ctx);
 
81d882d5
     ctx->co.flags |= CO_IGNORE_PACKET_ID;
3b185161
 
81d882d5
     assert_true(tls_crypt_wrap(&ctx->source, &ctx->ciphertext, &ctx->co));
     assert_true(BLEN(&ctx->source) < BLEN(&ctx->ciphertext));
     struct buffer tmp = ctx->ciphertext;
     assert_true(tls_crypt_unwrap(&tmp, &ctx->unwrapped, &ctx->co));
     buf_clear(&ctx->unwrapped);
     assert_true(tls_crypt_unwrap(&ctx->ciphertext, &ctx->unwrapped, &ctx->co));
3b185161
 }
 
a98a5676
 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();
 
     /* Sligthly 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));
 }
 
 /**
  * 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));
 }
 
81d882d5
 int
 main(void) {
3b185161
     const struct CMUnitTest tests[] = {
a98a5676
         cmocka_unit_test_setup_teardown(tls_crypt_loopback,
                                         test_tls_crypt_setup,
                                         test_tls_crypt_teardown),
81d882d5
         cmocka_unit_test_setup_teardown(tls_crypt_loopback_zero_len,
a98a5676
                                         test_tls_crypt_setup,
                                         test_tls_crypt_teardown),
81d882d5
         cmocka_unit_test_setup_teardown(tls_crypt_loopback_max_len,
a98a5676
                                         test_tls_crypt_setup,
                                         test_tls_crypt_teardown),
81d882d5
         cmocka_unit_test_setup_teardown(tls_crypt_fail_msg_too_long,
a98a5676
                                         test_tls_crypt_setup,
                                         test_tls_crypt_teardown),
81d882d5
         cmocka_unit_test_setup_teardown(tls_crypt_fail_invalid_key,
a98a5676
                                         test_tls_crypt_setup,
                                         test_tls_crypt_teardown),
81d882d5
         cmocka_unit_test_setup_teardown(tls_crypt_fail_replay,
a98a5676
                                         test_tls_crypt_setup,
                                         test_tls_crypt_teardown),
81d882d5
         cmocka_unit_test_setup_teardown(tls_crypt_ignore_replay,
a98a5676
                                         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),
3b185161
     };
 
 #if defined(ENABLE_CRYPTO_OPENSSL)
     OpenSSL_add_all_algorithms();
 #endif
 
     int ret = cmocka_run_group_tests_name("tls-crypt tests", tests, NULL, NULL);
 
 #if defined(ENABLE_CRYPTO_OPENSSL)
     EVP_cleanup();
 #endif
 
     return ret;
 }