summaryrefslogtreecommitdiffstats
path: root/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c')
-rw-r--r--source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c973
1 files changed, 973 insertions, 0 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c b/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c
new file mode 100644
index 0000000..e639d4c
--- /dev/null
+++ b/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c
@@ -0,0 +1,973 @@
+/*
+ Unit tests for the encrypted secrets code in encrypted_secrets.c
+
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2017
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <unistd.h>
+#include <cmocka.h>
+
+int ldb_encrypted_secrets_module_init(const char *version);
+#define TEST_ENCRYPTED_SECRETS
+#include "../encrypted_secrets.c"
+
+struct ldbtest_ctx {
+ struct tevent_context *ev;
+ struct ldb_context *ldb;
+ struct ldb_module *module;
+
+ const char *dbfile;
+ const char *lockfile; /* lockfile is separate */
+ const char *keyfile;
+
+ const char *dbpath;
+};
+
+/* -------------------------------------------------------------------------- */
+/*
+ * Replace the dsdb helper routines used by the operational_init function
+ *
+ */
+int dsdb_module_search_dn(
+ struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_result **_res,
+ struct ldb_dn *basedn,
+ const char * const *attrs,
+ uint32_t dsdb_flags,
+ struct ldb_request *parent)
+{
+ struct ldb_context *ldb = ldb_module_get_ctx(module);
+ struct ldb_message *msg = ldb_msg_new(ldb);
+ struct ldb_result *res = talloc_zero(mem_ctx, struct ldb_result);
+
+ msg->dn = ldb_dn_new(msg, ldb, "@SAMBA_DSDB");
+ ldb_msg_add_string(
+ msg,
+ SAMBA_REQUIRED_FEATURES_ATTR,
+ SAMBA_ENCRYPTED_SECRETS_FEATURE);
+
+ res->msgs = talloc_array(mem_ctx, struct ldb_message*, 1);
+ res->msgs[0] = msg;
+ *_res = res;
+ return LDB_SUCCESS;
+}
+
+int dsdb_module_reference_dn(
+ struct ldb_module *module,
+ TALLOC_CTX *mem_ctx,
+ struct ldb_dn *base,
+ const char *attribute,
+ struct ldb_dn **dn,
+ struct ldb_request *parent)
+{
+ return LDB_SUCCESS;
+}
+/* -------------------------------------------------------------------------- */
+
+static void unlink_old_db(struct ldbtest_ctx *test_ctx)
+{
+ int ret;
+
+ errno = 0;
+ ret = unlink(test_ctx->lockfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->dbfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+
+ errno = 0;
+ ret = unlink(test_ctx->keyfile);
+ if (ret == -1 && errno != ENOENT) {
+ fail();
+ }
+}
+
+static void write_key(void **state, DATA_BLOB key) {
+
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+ FILE *fp = NULL;
+ int written = 0;
+
+ fp = fopen(test_ctx->keyfile, "wb");
+ assert_non_null(fp);
+
+ written = fwrite(key.data, 1, key.length, fp);
+ assert_int_equal(written, key.length);
+ fclose(fp);
+}
+
+static const struct ldb_module_ops eol_ops = {
+ .name = "eol",
+ .search = NULL,
+ .add = NULL,
+ .modify = NULL,
+ .del = NULL,
+ .rename = NULL,
+ .init_context = NULL
+};
+
+static int setup(void **state)
+{
+ struct ldbtest_ctx *test_ctx = NULL;
+ struct ldb_module *eol = NULL;
+ int rc;
+
+ test_ctx = talloc_zero(NULL, struct ldbtest_ctx);
+ assert_non_null(test_ctx);
+
+ test_ctx->ev = tevent_context_init(test_ctx);
+ assert_non_null(test_ctx->ev);
+
+ test_ctx->ldb = ldb_init(test_ctx, test_ctx->ev);
+ assert_non_null(test_ctx->ldb);
+
+
+
+ test_ctx->module = ldb_module_new(
+ test_ctx,
+ test_ctx->ldb,
+ "encrypted_secrets",
+ &ldb_encrypted_secrets_module_ops);
+ assert_non_null(test_ctx->module);
+ eol = ldb_module_new(test_ctx, test_ctx->ldb, "eol", &eol_ops);
+ assert_non_null(eol);
+ ldb_module_set_next(test_ctx->module, eol);
+
+ test_ctx->dbfile = talloc_strdup(test_ctx, "apitest.ldb");
+ assert_non_null(test_ctx->dbfile);
+
+ test_ctx->lockfile = talloc_asprintf(test_ctx, "%s-lock",
+ test_ctx->dbfile);
+ assert_non_null(test_ctx->lockfile);
+
+ test_ctx->keyfile = talloc_strdup(test_ctx, SECRETS_KEY_FILE);
+ assert_non_null(test_ctx->keyfile);
+
+ test_ctx->dbpath = talloc_asprintf(test_ctx,
+ TEST_BE"://%s", test_ctx->dbfile);
+ assert_non_null(test_ctx->dbpath);
+
+ unlink_old_db(test_ctx);
+
+ rc = ldb_connect(test_ctx->ldb, test_ctx->dbpath, 0, NULL);
+ assert_int_equal(rc, 0);
+ *state = test_ctx;
+ return 0;
+}
+
+static int setup_with_key(void **state)
+{
+ struct ldbtest_ctx *test_ctx = NULL;
+ DATA_BLOB key = data_blob_null;
+ uint8_t key_data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ int rc;
+
+ setup(state);
+ key.data = key_data;
+ key.length = sizeof(key_data);
+
+ write_key(state, key);
+
+ test_ctx = talloc_get_type_abort(*state, struct ldbtest_ctx);
+ {
+ struct ldb_message *msg = ldb_msg_new(test_ctx->ldb);
+ msg->dn = ldb_dn_new(msg, test_ctx->ldb, "@SAMBA_DSDB");
+ ldb_msg_add_string(
+ msg,
+ SAMBA_REQUIRED_FEATURES_ATTR,
+ SAMBA_ENCRYPTED_SECRETS_FEATURE);
+ ldb_add(test_ctx->ldb, msg);
+ }
+
+ rc = es_init(test_ctx->module);
+ assert_int_equal(rc, LDB_SUCCESS);
+
+ return 0;
+}
+
+static int teardown(void **state)
+{
+ struct ldbtest_ctx *test_ctx = talloc_get_type_abort(*state,
+ struct ldbtest_ctx);
+
+ unlink_old_db(test_ctx);
+ talloc_free(test_ctx);
+ return 0;
+}
+/*
+ * No key file present.
+ *
+ * The key should be empty and encrypt_secrets should be false.
+ */
+static void test_no_key_file(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct es_data *data = NULL;
+
+ int rc;
+
+ rc = es_init(test_ctx->module);
+ assert_int_equal(rc, LDB_SUCCESS);
+
+ data = talloc_get_type(ldb_module_get_private(test_ctx->module),
+ struct es_data);
+
+ assert_false(data->encrypt_secrets);
+ assert_int_equal(0, data->keys[0].length);
+
+}
+
+/*
+ * Key file present.
+ *
+ * The key should be loaded and encrypt secrets should be true;
+ */
+static void test_key_file(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct es_data *data = NULL;
+ int rc;
+ DATA_BLOB key = data_blob_null;
+ uint8_t key_data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+
+ key.data = key_data;
+ key.length = sizeof(key_data);
+
+ write_key(state, key);
+
+
+ rc = es_init(test_ctx->module);
+ assert_int_equal(rc, LDB_SUCCESS);
+
+ data = talloc_get_type(ldb_module_get_private(test_ctx->module),
+ struct es_data);
+
+ assert_true(data->encrypt_secrets);
+ assert_int_equal(16, data->keys[0].length);
+ assert_int_equal(0, data_blob_cmp(&key, &data->keys[0]));
+
+}
+
+/*
+ * Key file present, short key.
+ *
+ * The key should be not be loaded and an error returned.
+ */
+static void test_key_file_short_key(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ int rc;
+ DATA_BLOB key = data_blob_null;
+ uint8_t key_data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e};
+
+ key.data = key_data;
+ key.length = sizeof(key_data);
+
+ write_key(state, key);
+
+
+ rc = es_init(test_ctx->module);
+ assert_int_equal(rc, LDB_ERR_OPERATIONS_ERROR);
+}
+
+/*
+ * Key file present, long key.
+ *
+ * Only the first 16 bytes of the key should be loaded.
+ */
+static void test_key_file_long_key(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct es_data *data = NULL;
+ int rc;
+ DATA_BLOB key = data_blob_null;
+ uint8_t key_data[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xf,
+ 0x10};
+
+ key.data = key_data;
+ key.length = sizeof(key_data);
+
+ write_key(state, key);
+
+ rc = es_init(test_ctx->module);
+ assert_int_equal(rc, LDB_SUCCESS);
+
+ data = talloc_get_type(ldb_module_get_private(test_ctx->module),
+ struct es_data);
+
+ assert_true(data->encrypt_secrets);
+ assert_int_equal(16, data->keys[0].length);
+
+ /*
+ * Should have only read the first 16 bytes of the written key
+ */
+ key.length = 16;
+ assert_int_equal(0, data_blob_cmp(&key, &data->keys[0]));
+}
+
+/*
+ * Test gnutls_encryption and decryption.
+ */
+static void test_gnutls_value_decryption(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ const struct ldb_val plain_text =
+ data_blob_string_const("A text value");
+ unsigned char iv_data[] = {
+ 0xe7, 0xa3, 0x85, 0x17, 0x45, 0x73, 0xf4, 0x25,
+ 0xa5, 0x56, 0xde, 0x4c,
+ };
+ unsigned char encrypted_data[] = {
+ 0xac, 0x13, 0x86, 0x94, 0x3b, 0xed, 0xf2, 0x51,
+ 0xec, 0x85, 0x4d, 0x00, 0x37, 0x81, 0x46, 0x15,
+ 0x42, 0x13, 0xb1, 0x69, 0x49, 0x10, 0xe7, 0x9e,
+ 0x15, 0xbd, 0x95, 0x75, 0x6b, 0x0c, 0xc0, 0xa4,
+ };
+ struct EncryptedSecret es = {
+ .iv = {
+ .data = iv_data,
+ .length = sizeof(iv_data),
+ },
+ .header = {
+ .magic = ENCRYPTED_SECRET_MAGIC_VALUE,
+ .version = SECRET_ATTRIBUTE_VERSION,
+ .algorithm = ENC_SECRET_AES_128_AEAD,
+ },
+ .encrypted = {
+ .data = encrypted_data,
+ .length = sizeof(encrypted_data),
+ }
+ };
+ unsigned char es_keys_blob[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ };
+ struct es_data data = {
+ .encrypt_secrets = true,
+ .keys[0] = {
+ .data = es_keys_blob,
+ .length = sizeof(es_keys_blob),
+ },
+ .encryption_algorithm = GNUTLS_CIPHER_AES_128_GCM,
+ };
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ int err = LDB_SUCCESS;
+
+ gnutls_decrypt_aead(&err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ &data);
+ assert_int_equal(LDB_SUCCESS, err);
+ assert_int_equal(plain_text.length, decrypted->cleartext.length);
+ assert_int_equal(0, data_blob_cmp(&decrypted->cleartext, &plain_text));
+}
+
+/*
+ * Test gnutls_encryption and decryption.
+ */
+static void test_gnutls_value_encryption(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct ldb_val plain_text = data_blob_null;
+ struct ldb_val cipher_text = data_blob_null;
+ struct EncryptedSecret es;
+
+ struct es_data *data = talloc_get_type(
+ ldb_module_get_private(test_ctx->module),
+ struct es_data);
+ int err = LDB_SUCCESS;
+ int rc;
+
+ plain_text = data_blob_string_const("A text value");
+ cipher_text = gnutls_encrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ plain_text,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+
+ rc = ndr_pull_struct_blob(
+ &cipher_text,
+ test_ctx,
+ &es,
+ (ndr_pull_flags_fn_t) ndr_pull_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_true(check_header(&es));
+
+ {
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ gnutls_decrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+ assert_int_equal(
+ plain_text.length,
+ decrypted->cleartext.length);
+ assert_int_equal(0,
+ data_blob_cmp(
+ &decrypted->cleartext,
+ &plain_text));
+ }
+}
+
+static void test_gnutls_altered_header(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct ldb_val plain_text = data_blob_null;
+ struct ldb_val cipher_text = data_blob_null;
+ struct EncryptedSecret es;
+
+ struct es_data *data = talloc_get_type(
+ ldb_module_get_private(test_ctx->module),
+ struct es_data);
+ int err = LDB_SUCCESS;
+ int rc;
+
+ plain_text = data_blob_string_const("A text value");
+ cipher_text = gnutls_encrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ plain_text,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+
+ rc = ndr_pull_struct_blob(
+ &cipher_text,
+ test_ctx,
+ &es,
+ (ndr_pull_flags_fn_t) ndr_pull_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_true(check_header(&es));
+
+ {
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ gnutls_decrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+ assert_int_equal(
+ plain_text.length,
+ decrypted->cleartext.length);
+ assert_int_equal(0,
+ data_blob_cmp(
+ &decrypted->cleartext,
+ &plain_text));
+ }
+ es.header.flags = es.header.flags ^ 0xffffffff;
+ {
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ gnutls_decrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ data);
+ assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err);
+ }
+}
+
+static void test_gnutls_altered_data(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct ldb_val plain_text = data_blob_null;
+ struct ldb_val cipher_text = data_blob_null;
+ struct EncryptedSecret es;
+
+ struct es_data *data = talloc_get_type(
+ ldb_module_get_private(test_ctx->module),
+ struct es_data);
+ int err = LDB_SUCCESS;
+ int rc;
+
+ plain_text = data_blob_string_const("A text value");
+ cipher_text = gnutls_encrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ plain_text,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+
+ rc = ndr_pull_struct_blob(
+ &cipher_text,
+ test_ctx,
+ &es,
+ (ndr_pull_flags_fn_t) ndr_pull_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_true(check_header(&es));
+
+ {
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ gnutls_decrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+ assert_int_equal(
+ plain_text.length,
+ decrypted->cleartext.length);
+ assert_int_equal(0,
+ data_blob_cmp(
+ &decrypted->cleartext,
+ &plain_text));
+ }
+ es.encrypted.data[0] = es.encrypted.data[0] ^ 0xff;
+ {
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ gnutls_decrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ data);
+ assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err);
+ }
+}
+
+static void test_gnutls_altered_iv(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct ldb_val plain_text = data_blob_null;
+ struct ldb_val cipher_text = data_blob_null;
+ struct EncryptedSecret es;
+
+ struct es_data *data = talloc_get_type(
+ ldb_module_get_private(test_ctx->module),
+ struct es_data);
+ int err = LDB_SUCCESS;
+ int rc;
+
+ plain_text = data_blob_string_const("A text value");
+ cipher_text = gnutls_encrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ plain_text,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+
+ rc = ndr_pull_struct_blob(
+ &cipher_text,
+ test_ctx,
+ &es,
+ (ndr_pull_flags_fn_t) ndr_pull_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_true(check_header(&es));
+
+ {
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ gnutls_decrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ data);
+ assert_int_equal(LDB_SUCCESS, err);
+ assert_int_equal(
+ plain_text.length,
+ decrypted->cleartext.length);
+ assert_int_equal(0,
+ data_blob_cmp(
+ &decrypted->cleartext,
+ &plain_text));
+ }
+ es.iv.data[0] = es.iv.data[0] ^ 0xff;
+ {
+ struct PlaintextSecret *decrypted =
+ talloc_zero(test_ctx, struct PlaintextSecret);
+ gnutls_decrypt_aead(
+ &err,
+ test_ctx,
+ test_ctx->ldb,
+ &es,
+ decrypted,
+ data);
+ assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err);
+ }
+}
+
+/*
+ * Test samba encryption and decryption and decryption.
+ */
+
+/*
+ * Test message encryption.
+ * Test the secret attributes of a message are encrypted and decrypted.
+ * Test that the non secret attributes are not encrypted.
+ *
+ */
+static void test_message_encryption_decryption(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct ldb_context *ldb = test_ctx->ldb;
+ const char * const secrets[] = {DSDB_SECRET_ATTRIBUTES};
+ const size_t num_secrets
+ = (sizeof(secrets)/sizeof(secrets[0]));
+ struct ldb_message *msg = ldb_msg_new(ldb);
+ const struct ldb_message *encrypted_msg = NULL;
+ struct es_data *data = talloc_get_type(
+ ldb_module_get_private(test_ctx->module),
+ struct es_data);
+ struct ldb_message_element *el = NULL;
+ int ret = LDB_SUCCESS;
+ size_t i;
+ unsigned int j;
+
+ msg->dn = ldb_dn_new(msg, ldb, "dc=test");
+ ldb_msg_add_string(msg, "cmocka_test_name01", "value01");
+ for (i=0; i < num_secrets; i++) {
+ ldb_msg_add_string(
+ msg,
+ secrets[i],
+ secrets[i]);
+ }
+ ldb_msg_add_string(msg, "cmocka_test_name02", "value02");
+
+ encrypted_msg = encrypt_secret_attributes(
+ &ret,
+ test_ctx,
+ test_ctx->ldb,
+ msg,
+ data);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ /*
+ * Check that all the secret attributes have been encrypted
+ *
+ */
+ for (i=0; i < num_secrets; i++) {
+ el = ldb_msg_find_element(encrypted_msg, secrets[i]);
+ assert_non_null(el);
+ for (j = 0; j < el->num_values; j++) {
+ int rc = LDB_SUCCESS;
+ struct ldb_val dc = decrypt_value(
+ &rc,
+ test_ctx,
+ test_ctx->ldb,
+ el->values[j],
+ data);
+ assert_int_equal(LDB_SUCCESS, rc);
+ assert_memory_equal(
+ secrets[i],
+ dc.data,
+ dc.length);
+ TALLOC_FREE(dc.data);
+ }
+ }
+
+ /*
+ * Check that the normal attributes have not been encrypted
+ */
+ el = ldb_msg_find_element(encrypted_msg, "cmocka_test_name01");
+ assert_non_null(el);
+ assert_memory_equal(
+ "value01",
+ el->values[0].data,
+ el->values[0].length);
+
+ el = ldb_msg_find_element(encrypted_msg, "cmocka_test_name02");
+ assert_non_null(el);
+ assert_memory_equal(
+ "value02",
+ el->values[0].data,
+ el->values[0].length);
+
+ /*
+ * Now decrypt the message
+ */
+ ret = decrypt_secret_attributes(test_ctx->ldb,
+ discard_const(encrypted_msg),
+ data);
+ assert_int_equal(LDB_SUCCESS, ret);
+
+ /*
+ * Check that all the secret attributes have been decrypted
+ */
+ for (i=0; i < num_secrets; i++) {
+ el = ldb_msg_find_element(encrypted_msg, secrets[i]);
+ assert_non_null(el);
+ for (j = 0; j < el->num_values; j++) {
+ assert_memory_equal(
+ secrets[i],
+ el->values[j].data,
+ el->values[j].length);
+ }
+ }
+
+ /*
+ * Check that the normal attributes are intact
+ */
+ el = ldb_msg_find_element(msg, "cmocka_test_name01");
+ assert_non_null(el);
+ assert_memory_equal(
+ "value01",
+ el->values[0].data,
+ el->values[0].length);
+
+ el = ldb_msg_find_element(msg, "cmocka_test_name02");
+ assert_non_null(el);
+ assert_memory_equal(
+ "value02",
+ el->values[0].data,
+ el->values[0].length);
+
+}
+
+static void test_check_header(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+
+ struct ldb_val enc = data_blob_null;
+ struct EncryptedSecret *es = NULL;
+ int rc;
+
+ /*
+ * Valid EncryptedSecret
+ */
+ es = makeEncryptedSecret(test_ctx->ldb, test_ctx);
+ rc = ndr_push_struct_blob(
+ &enc,
+ test_ctx,
+ es,
+ (ndr_push_flags_fn_t) ndr_push_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_true(check_header(es));
+ TALLOC_FREE(enc.data);
+ TALLOC_FREE(es);
+
+ /*
+ * invalid magic value
+ */
+ es = makeEncryptedSecret(test_ctx->ldb, test_ctx);
+ es->header.magic = 0xca5cadee;
+ rc = ndr_push_struct_blob(
+ &enc,
+ test_ctx,
+ es,
+ (ndr_push_flags_fn_t) ndr_push_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_false(check_header(es));
+ TALLOC_FREE(enc.data);
+ TALLOC_FREE(es);
+
+ /*
+ * invalid version
+ */
+ es = makeEncryptedSecret(test_ctx->ldb, test_ctx);
+ es->header.version = SECRET_ATTRIBUTE_VERSION + 1;
+ rc = ndr_push_struct_blob(
+ &enc,
+ test_ctx,
+ es,
+ (ndr_push_flags_fn_t) ndr_push_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_false(check_header(es));
+ TALLOC_FREE(enc.data);
+ TALLOC_FREE(es);
+
+ /*
+ * invalid algorithm
+ */
+ es = makeEncryptedSecret(test_ctx->ldb, test_ctx);
+ es->header.algorithm = SECRET_ENCRYPTION_ALGORITHM + 1;
+ rc = ndr_push_struct_blob(
+ &enc,
+ test_ctx,
+ es,
+ (ndr_push_flags_fn_t) ndr_push_EncryptedSecret);
+ assert_true(NDR_ERR_CODE_IS_SUCCESS(rc));
+ assert_false(check_header(es));
+ TALLOC_FREE(enc.data);
+ TALLOC_FREE(es);
+}
+
+/*
+ * Attempt to decrypt a message containing an unencrypted secret attribute
+ * this should fail
+ */
+static void test_unencrypted_secret(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ struct ldb_context *ldb = test_ctx->ldb;
+ struct ldb_message *msg = ldb_msg_new(ldb);
+ struct es_data *data = talloc_get_type(
+ ldb_module_get_private(test_ctx->module),
+ struct es_data);
+ int ret = LDB_SUCCESS;
+
+ msg->dn = ldb_dn_new(msg, ldb, "dc=test");
+ ldb_msg_add_string(msg, "unicodePwd", "value01");
+
+ ret = decrypt_secret_attributes(test_ctx->ldb, msg, data);
+ assert_int_equal(LDB_ERR_OPERATIONS_ERROR, ret);
+}
+
+/*
+ * Test full decryption of a static value with static key
+ */
+static void test_record_decryption(void **state)
+{
+ struct ldbtest_ctx *test_ctx =
+ talloc_get_type_abort(*state, struct ldbtest_ctx);
+ unsigned char plain_data[] = {
+ 0xe6, 0xa6, 0xb8, 0xff, 0xdf, 0x06, 0x6c, 0xe3,
+ 0xea, 0xd0, 0x94, 0xbb, 0x79, 0xbd, 0x0a, 0x24
+ };
+ unsigned char encrypted_data[] = {
+ 0x0c, 0x00, 0x00, 0x00, 0x33, 0x91, 0x74, 0x25,
+ 0x26, 0xcc, 0x0b, 0x8c, 0x21, 0xc1, 0x13, 0xe2,
+ 0xed, 0xad, 0x5c, 0xca, 0x01, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x1a, 0xdc, 0xc9, 0x11, 0x08, 0xca, 0x2c, 0xfb,
+ 0xc8, 0x32, 0x6b, 0x1b, 0x25, 0x7f, 0x52, 0xbb,
+ 0xae, 0x9b, 0x88, 0x52, 0xb0, 0x18, 0x6d, 0x9d,
+ 0x9b, 0xdd, 0xcd, 0x1b, 0x5f, 0x4a, 0x5c, 0x29,
+ 0xca, 0x0b, 0x36, 0xaa
+ };
+ struct ldb_val cipher_text
+ = data_blob_const(encrypted_data,
+ sizeof(encrypted_data));
+ unsigned char es_keys_blob[] = {
+ 0x1d, 0xae, 0xf5, 0xaa, 0xa3, 0x85, 0x0d, 0x0a,
+ 0x8c, 0x24, 0x5c, 0x4c, 0xa7, 0x0f, 0x81, 0x79
+ };
+ struct es_data data = {
+ .encrypt_secrets = true,
+ .keys[0] = {
+ .data = es_keys_blob,
+ .length = sizeof(es_keys_blob),
+ },
+ .encryption_algorithm = GNUTLS_CIPHER_AES_128_GCM,
+ };
+ int err = LDB_SUCCESS;
+ struct ldb_val dec = decrypt_value(&err, test_ctx, test_ctx->ldb, cipher_text,
+ &data);
+ assert_int_equal(LDB_SUCCESS, err);
+ assert_int_equal(sizeof(plain_data), dec.length);
+ assert_memory_equal(dec.data, plain_data, sizeof(plain_data));
+}
+
+
+int main(void) {
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test_setup_teardown(
+ test_no_key_file,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_key_file,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_key_file_short_key,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_key_file_long_key,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_check_header,
+ setup,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_gnutls_value_decryption,
+ setup_with_key,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_gnutls_value_encryption,
+ setup_with_key,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_gnutls_altered_header,
+ setup_with_key,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_gnutls_altered_data,
+ setup_with_key,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_gnutls_altered_iv,
+ setup_with_key,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_message_encryption_decryption,
+ setup_with_key,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_unencrypted_secret,
+ setup_with_key,
+ teardown),
+ cmocka_unit_test_setup_teardown(
+ test_record_decryption,
+ setup_with_key,
+ teardown),
+ };
+
+ cmocka_set_message_output(CM_OUTPUT_SUBUNIT);
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}