From d2a0904b915c4f9ffe8ca7f8015ef201dd8b827d Mon Sep 17 00:00:00 2001 From: Andrew Bartlett Date: Wed, 31 Jul 2019 16:37:00 +1200 Subject: [PATCH 108/187] s4-samdb: Remove duplicate encrypted_secrets code using internal Samba AES We now rely on GnuTLS 3.4.7 or later. Signed-off-by: Andrew Bartlett Reviewed-by: Andreas Schneider (cherry picked from commit 85a1c4973921fdf9412ec56a3ed6a77f3ab84116) --- .../samdb/ldb_modules/encrypted_secrets.c | 266 +---------------- .../tests/test_encrypted_secrets.c | 278 ------------------ 2 files changed, 2 insertions(+), 542 deletions(-) diff --git a/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c b/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c index e0932858588..0d46031ec64 100644 --- a/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c +++ b/source4/dsdb/samdb/ldb_modules/encrypted_secrets.c @@ -39,22 +39,8 @@ #include "dsdb/samdb/samdb.h" #include "dsdb/samdb/ldb_modules/util.h" -/* Build either with GnuTLS crypto or Samba crypto. */ -#ifdef HAVE_GNUTLS_AEAD - #define BUILD_WITH_GNUTLS_AEAD -#else /* !HAVE_GNUTLS_AEAD */ - #define BUILD_WITH_SAMBA_AES_GCM -#endif /* HAVE_GNUTLS_AEAD */ - -#ifdef BUILD_WITH_GNUTLS_AEAD - #include - #include -#endif /* BUILD_WITH_GNUTLS_AEAD */ - -#ifdef BUILD_WITH_SAMBA_AES_GCM - #include "lib/crypto/aes.h" - #include "lib/crypto/aes_gcm_128.h" -#endif /* BUILD_WITH_SAMBA_AES_GCM */ +#include +#include static const char * const secret_attributes[] = {DSDB_SECRET_ATTRIBUTES}; static const size_t num_secret_attributes = ARRAY_SIZE(secret_attributes); @@ -74,12 +60,10 @@ struct es_data { * Encryption keys for secret attributes */ DATA_BLOB keys[NUMBER_OF_KEYS]; -#ifdef BUILD_WITH_GNUTLS_AEAD /* * The gnutls algorithm used to encrypt attributes */ int encryption_algorithm; -#endif /* BUILD_WITH_GNUTLS_AEAD */ }; /* @@ -262,9 +246,7 @@ static int load_keys(struct ldb_module *module, struct es_data *data) data->keys[0] = key; data->encrypt_secrets = true; -#ifdef BUILD_WITH_GNUTLS_AEAD data->encryption_algorithm = GNUTLS_CIPHER_AES_128_GCM; -#endif TALLOC_FREE(frame); return LDB_SUCCESS; @@ -299,7 +281,6 @@ static bool should_encrypt(const struct ldb_message_element *el) * * @return Size rounded up to the nearest multiple of block_size */ -#ifdef BUILD_WITH_GNUTLS_AEAD static size_t round_to_block_size(size_t block_size, size_t size) { if ((size % block_size) == 0) { @@ -308,7 +289,6 @@ static size_t round_to_block_size(size_t block_size, size_t size) return ((int)(size/block_size) + 1) * block_size; } } -#endif /* BUILD_WITH_GNUTLS_AEAD */ /* * @brief Create an new EncryptedSecret owned by the supplied talloc context. @@ -375,239 +355,6 @@ static DATA_BLOB makePlainText(TALLOC_CTX *ctx, return pt; } -#ifdef BUILD_WITH_SAMBA_AES_GCM -/* - * @brief Encrypt an ldb value using an aead algorithm. - * - * This function uses the samba internal implementation to perform the encryption. However - * the encrypted data and tag are stored in a manner compatible with gnutls, - * so the gnutls aead functions can be used to decrypt and verify the data. - * - * @param err Pointer to an error code, set to: - * LDB_SUCESS If the value was successfully encrypted - * LDB_ERR_OPERATIONS_ERROR If there was an error. - * - * @param ctx Talloc memory context the will own the memory allocated - * @param ldb ldb context, to allow logging. - * @param val The ldb value to encrypt, not altered or freed - * @param data The context data for this module. - * - * @return The encrypted ldb_val, or data_blob_null if there was an error. - */ -static struct ldb_val samba_encrypt_aead(int *err, - TALLOC_CTX *ctx, - struct ldb_context *ldb, - const struct ldb_val val, - const struct es_data *data) -{ - struct aes_gcm_128_context cctx; - struct EncryptedSecret *es = NULL; - DATA_BLOB pt = data_blob_null; - struct ldb_val enc = data_blob_null; - DATA_BLOB key_blob = data_blob_null; - int rc; - TALLOC_CTX *frame = talloc_stackframe(); - - es = makeEncryptedSecret(ldb, frame); - if (es == NULL) { - goto error_exit; - } - - pt = makePlainText(frame, ldb, val); - if (pt.length == 0) { - goto error_exit; - } - - /* - * Set the encryption key - */ - key_blob = get_key(data); - if (key_blob.length != AES_BLOCK_SIZE) { - ldb_asprintf_errstring(ldb, - "Invalid EncryptedSecrets key size, " - "expected %u bytes and is %zu bytes\n", - AES_BLOCK_SIZE, - key_blob.length); - goto error_exit; - } - - /* - * Set the initialisation vector - */ - { - uint8_t *iv = talloc_zero_size(frame, AES_GCM_128_IV_SIZE); - if (iv == NULL) { - ldb_set_errstring(ldb, - "Out of memory allocating iv\n"); - goto error_exit; - } - - generate_nonce_buffer(iv, AES_GCM_128_IV_SIZE); - - es->iv.length = AES_GCM_128_IV_SIZE; - es->iv.data = iv; - } - - /* - * Encrypt the value, and append the GCM digest to the encrypted - * data so that it can be decrypted and validated by the - * gnutls aead decryption routines. - */ - { - uint8_t *ct = talloc_zero_size(frame, pt.length + AES_BLOCK_SIZE); - if (ct == NULL) { - ldb_oom(ldb); - goto error_exit; - } - - memcpy(ct, pt.data, pt.length); - es->encrypted.length = pt.length + AES_BLOCK_SIZE; - es->encrypted.data = ct; - } - - aes_gcm_128_init(&cctx, key_blob.data, es->iv.data); - aes_gcm_128_updateA(&cctx, - (uint8_t *)&es->header, - sizeof(struct EncryptedSecretHeader)); - aes_gcm_128_crypt(&cctx, es->encrypted.data, pt.length); - aes_gcm_128_updateC(&cctx, es->encrypted.data, pt.length); - aes_gcm_128_digest(&cctx, &es->encrypted.data[pt.length]); - - rc = ndr_push_struct_blob(&enc, - ctx, - es, - (ndr_push_flags_fn_t) - ndr_push_EncryptedSecret); - if (!NDR_ERR_CODE_IS_SUCCESS(rc)) { - ldb_set_errstring(ldb, - "Unable to ndr push EncryptedSecret\n"); - goto error_exit; - } - TALLOC_FREE(frame); - return enc; - -error_exit: - *err = LDB_ERR_OPERATIONS_ERROR; - TALLOC_FREE(frame); - return data_blob_null; -} - -/* - * @brief Decrypt data encrypted using an aead algorithm. - * - * Decrypt the data in ed and insert it into ev. The data was encrypted - * with the samba aes gcm implementation. - * - * @param err Pointer to an error code, set to: - * LDB_SUCESS If the value was successfully decrypted - * LDB_ERR_OPERATIONS_ERROR If there was an error. - * - * @param ctx Talloc memory context that will own the memory allocated - * @param ldb ldb context, to allow logging. - * @param ev The value to be updated with the decrypted data. - * @param ed The data to decrypt. - * @param data The context data for this module. - * - * @return ev is updated with the unencrypted data. - */ -static void samba_decrypt_aead(int *err, - TALLOC_CTX *ctx, - struct ldb_context *ldb, - struct EncryptedSecret *es, - struct PlaintextSecret *ps, - const struct es_data *data) -{ - struct aes_gcm_128_context cctx; - DATA_BLOB pt = data_blob_null; - DATA_BLOB key_blob = data_blob_null; - uint8_t sig[AES_BLOCK_SIZE] = {0, }; - int rc; - int cmp; - TALLOC_CTX *frame = talloc_stackframe(); - - /* - * Set the encryption key - */ - key_blob = get_key(data); - if (key_blob.length != AES_BLOCK_SIZE) { - ldb_asprintf_errstring(ldb, - "Invalid EncryptedSecrets key size, " - "expected %u bytes and is %zu bytes\n", - AES_BLOCK_SIZE, - key_blob.length); - goto error_exit; - } - - if (es->iv.length < AES_GCM_128_IV_SIZE) { - ldb_asprintf_errstring(ldb, - "Invalid EncryptedSecrets iv size, " - "expected %u bytes and is %zu bytes\n", - AES_GCM_128_IV_SIZE, - es->iv.length); - goto error_exit; - } - - if (es->encrypted.length < AES_BLOCK_SIZE) { - ldb_asprintf_errstring(ldb, - "Invalid EncryptedData size, " - "expected %u bytes and is %zu bytes\n", - AES_BLOCK_SIZE, - es->encrypted.length); - goto error_exit; - } - - pt.length = es->encrypted.length - AES_BLOCK_SIZE; - pt.data = talloc_zero_size(ctx, pt.length); - if (pt.data == NULL) { - ldb_set_errstring(ldb, - "Out of memory allocating space for " - "plain text\n"); - goto error_exit; - } - memcpy(pt.data, es->encrypted.data, pt.length); - - aes_gcm_128_init(&cctx, key_blob.data, es->iv.data); - aes_gcm_128_updateA(&cctx, - (uint8_t *)&es->header, - sizeof(struct EncryptedSecretHeader)); - aes_gcm_128_updateC(&cctx, pt.data, pt.length); - aes_gcm_128_crypt(&cctx, pt.data, pt.length); - aes_gcm_128_digest(&cctx, sig); - - /* - * Check the authentication tag - */ - cmp = memcmp(&es->encrypted.data[pt.length], sig, AES_BLOCK_SIZE); - if (cmp != 0) { - ldb_set_errstring(ldb, - "Tag does not match, " - "data corrupted or altered\n"); - goto error_exit; - } - - rc = ndr_pull_struct_blob(&pt, - ctx, - ps, - (ndr_pull_flags_fn_t) - ndr_pull_PlaintextSecret); - if(!NDR_ERR_CODE_IS_SUCCESS(rc)) { - ldb_asprintf_errstring(ldb, - "Error(%d) unpacking decrypted data, " - "data possibly corrupted or altered\n", - rc); - goto error_exit; - } - TALLOC_FREE(frame); - return; - -error_exit: - *err = LDB_ERR_OPERATIONS_ERROR; - TALLOC_FREE(frame); - return; -} -#endif /* BUILD_WITH_SAMBA_AES_GCM */ - -#ifdef BUILD_WITH_GNUTLS_AEAD /* * Helper function converts a data blob to a gnutls_datum_t. @@ -946,7 +693,6 @@ error_exit: *err = LDB_ERR_OPERATIONS_ERROR; return; } -#endif /* BUILD_WITH_GNUTLS_AEAD */ /* * @brief Encrypt an attribute value using the default encryption algorithm. @@ -972,11 +718,7 @@ static struct ldb_val encrypt_value(int *err, const struct ldb_val val, const struct es_data *data) { -#ifdef BUILD_WITH_GNUTLS_AEAD return gnutls_encrypt_aead(err, ctx, ldb, val, data); -#elif defined BUILD_WITH_SAMBA_AES_GCM - return samba_encrypt_aead(err, ctx, ldb, val, data); -#endif } /* @@ -1206,11 +948,7 @@ static struct ldb_val decrypt_value(int *err, *err = LDB_ERR_OPERATIONS_ERROR; return data_blob_null; } -#ifdef BUILD_WITH_GNUTLS_AEAD gnutls_decrypt_aead(err, frame, ldb, &es, &ps, data); -#elif defined BUILD_WITH_SAMBA_AES_GCM - samba_decrypt_aead(err, frame, ldb, &es, &ps, data); -#endif if (*err != LDB_SUCCESS) { TALLOC_FREE(frame); diff --git a/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c b/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c index a33781d703d..b9516815f75 100644 --- a/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c +++ b/source4/dsdb/samdb/ldb_modules/tests/test_encrypted_secrets.c @@ -336,7 +336,6 @@ static void test_key_file_long_key(void **state) assert_int_equal(0, data_blob_cmp(&key, &data->keys[0])); } -#ifdef HAVE_GNUTLS_AEAD /* * Test gnutls_encryption and decryption. */ @@ -391,9 +390,7 @@ static void test_gnutls_value_encryption(void **state) &plain_text)); } } -#endif /* HAVE_GNUTLS_AEAD */ -#ifdef HAVE_GNUTLS_AEAD static void test_gnutls_altered_header(void **state) { struct ldbtest_ctx *test_ctx = @@ -458,9 +455,7 @@ static void test_gnutls_altered_header(void **state) assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err); } } -#endif /* HAVE_GNUTLS_AEAD */ -#ifdef HAVE_GNUTLS_AEAD static void test_gnutls_altered_data(void **state) { struct ldbtest_ctx *test_ctx = @@ -525,9 +520,7 @@ static void test_gnutls_altered_data(void **state) assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err); } } -#endif /* HAVE_GNUTLS_AEAD */ -#ifdef HAVE_GNUTLS_AEAD static void test_gnutls_altered_iv(void **state) { struct ldbtest_ctx *test_ctx = @@ -592,260 +585,10 @@ static void test_gnutls_altered_iv(void **state) assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err); } } -#endif /* HAVE_GNUTLS_AEAD */ /* * Test samba encryption and decryption and decryption. */ -#ifndef HAVE_GNUTLS_AEAD -static void test_samba_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 = samba_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); - samba_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_samba_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 = samba_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); - samba_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); - samba_decrypt_aead( - &err, - test_ctx, - test_ctx->ldb, - &es, - decrypted, - data); - assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err); - } -} - -static void test_samba_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 = samba_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); - samba_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); - samba_decrypt_aead( - &err, - test_ctx, - test_ctx->ldb, - &es, - decrypted, - data); - assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err); - } -} - -static void test_samba_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 = samba_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); - samba_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); - samba_decrypt_aead( - &err, - test_ctx, - test_ctx->ldb, - &es, - decrypted, - data); - assert_int_equal(LDB_ERR_OPERATIONS_ERROR, err); - } -} -#endif /* * Test message encryption. @@ -1096,9 +839,7 @@ static void test_record_decryption(void **state) .data = es_keys_blob, .length = sizeof(es_keys_blob), }, -#ifdef HAVE_GNUTLS_AEAD .encryption_algorithm = GNUTLS_CIPHER_AES_128_GCM, -#endif }; int err = LDB_SUCCESS; struct ldb_val dec = decrypt_value(&err, test_ctx, test_ctx->ldb, cipher_text, @@ -1131,7 +872,6 @@ int main(void) { test_check_header, setup, teardown), -#ifdef HAVE_GNUTLS_AEAD cmocka_unit_test_setup_teardown( test_gnutls_value_encryption, setup_with_key, @@ -1148,24 +888,6 @@ int main(void) { test_gnutls_altered_iv, setup_with_key, teardown), -#else - cmocka_unit_test_setup_teardown( - test_samba_value_encryption, - setup_with_key, - teardown), - cmocka_unit_test_setup_teardown( - test_samba_altered_header, - setup_with_key, - teardown), - cmocka_unit_test_setup_teardown( - test_samba_altered_data, - setup_with_key, - teardown), - cmocka_unit_test_setup_teardown( - test_samba_altered_iv, - setup_with_key, - teardown), -#endif /* HAVE_GNUTLS_AEAD */ cmocka_unit_test_setup_teardown( test_message_encryption_decryption, setup_with_key, -- 2.23.0