From: Aki Tuomi Date: Thu, 29 Aug 2024 13:04:04 +0000 (+0300) Subject: var-expand-crypt: Convert to new var_expand X-Git-Tag: 2.4.1~582 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d47d14f204694e1db026fb5c06d5e02e110d599c;p=thirdparty%2Fdovecot%2Fcore.git var-expand-crypt: Convert to new var_expand --- diff --git a/src/plugins/var-expand-crypt/Makefile.am b/src/plugins/var-expand-crypt/Makefile.am index d220979f1d..8b198f243e 100644 --- a/src/plugins/var-expand-crypt/Makefile.am +++ b/src/plugins/var-expand-crypt/Makefile.am @@ -1,4 +1,5 @@ AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib-var-expand \ -I$(top_srcdir)/src/lib \ -I$(top_srcdir)/src/lib-test \ -I$(top_srcdir)/src/lib-dcrypt @@ -24,6 +25,7 @@ lib20_var_expand_crypt_la_SOURCES = \ test_programs = test-var-expand-crypt test_var_expand_crypt_CFLAGS = \ + $(AM_CPPFLAGS) \ -DDCRYPT_BUILD_DIR=\"$(top_builddir)/src/lib-dcrypt\" test_var_expand_crypt_SOURCES = \ test-var-expand-crypt.c diff --git a/src/plugins/var-expand-crypt/test-var-expand-crypt.c b/src/plugins/var-expand-crypt/test-var-expand-crypt.c index 72c564aece..5564cfacde 100644 --- a/src/plugins/var-expand-crypt/test-var-expand-crypt.c +++ b/src/plugins/var-expand-crypt/test-var-expand-crypt.c @@ -3,7 +3,7 @@ #include "lib.h" #include "test-common.h" #include "str.h" -#include "var-expand.h" +#include "var-expand-new.h" #include "randgen.h" #include "dcrypt.h" @@ -15,28 +15,29 @@ extern void var_expand_crypt_deinit(void); static void test_var_expand_crypt(void) { struct var_expand_table table[] = { - { '\0', "98b3b40a48ca40f998b3b40a48ca40f9", "iv" }, - { '\0', "cc2981c8f38aea59cc2981c8f38aea59", "key" }, - { '\0', "46b58741763fe22598014be26331a082", "encrypted_noiv" }, - { '\0', "98b3b40a48ca40f998b3b40a48ca40f9$46b58741763fe22598014be26331a082$", "encrypted" }, - { '\0', "hello, world", "decrypted" }, - { '\0', NULL, "encrypted2" }, - { '\0', NULL, NULL } + { .key = "iv", .value = "98b3b40a48ca40f998b3b40a48ca40f9" }, + { .key = "key", .value = "cc2981c8f38aea59cc2981c8f38aea59" }, + { .key = "encrypted_raw", .value = "46b58741763fe22598014be26331a082" }, + { .key = "encrypted", .value = "98b3b40a48ca40f998b3b40a48ca40f9$46b58741763fe22598014be26331a082$" }, + { .key = "decrypted", .value = "hello, world" }, + { .key = "encrypted2", .value = NULL }, + { NULL, NULL, NULL } + }; + const struct var_expand_params params = { + .table = table, }; - static struct { + const struct { const char *input; const char *output; int expect_ret; } test_cases[] = { - { "%{encrypt;algo=null:decrypted}", "", -1 }, - { "%{encrypt;algo=aes-128-cbc,iv=98b3b40a48ca40f998b3b40a48ca40f9,key=cc2981c8f38aea59cc2981c8f38aea59:decrypted}", "98b3b40a48ca40f998b3b40a48ca40f9$46b58741763fe22598014be26331a082$", 1 }, - { "%{encrypt;noiv=yes,algo=aes-128-cbc,iv=98b3b40a48ca40f998b3b40a48ca40f9,key=cc2981c8f38aea59cc2981c8f38aea59:decrypted}", "46b58741763fe22598014be26331a082", 1 }, - { "%{encrypt;algo=aes-128-cbc,iv=%{iv},key=%{key}:decrypted}", "98b3b40a48ca40f998b3b40a48ca40f9$46b58741763fe22598014be26331a082$", 1 }, - { "%{decrypt;algo=null:encrypted}", "", -1 }, - { "%{decrypt;algo=aes-128-cbc,key=%{key}:encrypted}", "hello, world", 1 }, - { "%{decrypt;algo=aes-128-cbc,iv=%{iv},key=%{key}:encrypted_noiv}", "hello, world", 1 }, - { "%{decrypt;algo=aes-128-cbc,iv=98b3b40a48ca40f998b3b40a48ca40f9,key=cc2981c8f38aea59cc2981c8f38aea59:encrypted_noiv}", "hello, world", 1 }, + { "%{decrypted|encrypt(algorithm='null')}", "", -1 }, + { "%{decrypted|encrypt(algorithm='aes-128-cbc',iv=iv,key=key)}", "98b3b40a48ca40f998b3b40a48ca40f9$46b58741763fe22598014be26331a082$", 0 }, + { "%{decrypted|encrypt(algorithm='aes-128-cbc',iv=iv,key=key,raw=1)|hexlify}", "46b58741763fe22598014be26331a082", 0 }, + { "%{encrypted|decrypt(algorithm='null')}", "", -1 }, + { "%{encrypted|decrypt(algorithm='aes-128-cbc',key=key)}", "hello, world", 0 }, + { "%{encrypted_raw|unhexlify|decrypt(algorithm='aes-128-cbc',iv=iv,key=key,raw=1)}", "hello, world", 0 }, }; unsigned int i; @@ -47,15 +48,14 @@ static void test_var_expand_crypt(void) for(i=0; i < N_ELEMENTS(test_cases); i++) T_BEGIN { const char *error; string_t *dest = t_str_new(32); - int ret = var_expand_with_table(dest, test_cases[i].input, - table, &error); + int ret = var_expand_new(dest, test_cases[i].input, ¶ms, &error); if (ret < 0) { if (test_cases[i].expect_ret == -1) i_info("Expected: var_expand(%s): %s", test_cases[i].input, error); else i_error("var_expand(%s): %s", test_cases[i].input, error); } - test_assert_idx(strcmp(str_c(dest), test_cases[i].output)==0, i); + test_assert_strcmp_idx(str_c(dest), test_cases[i].output, i); test_assert_idx(ret == test_cases[i].expect_ret, i); } T_END; @@ -71,10 +71,10 @@ static void test_var_expand_crypt(void) str_truncate(input, 0); str_truncate(output, 0); - test_assert_idx(var_expand_with_table(input, "%{encrypt;algo=aes-128-cbc,key=%{key}:decrypted}", table, &error) == 1, i); + test_assert_idx(var_expand_new(input, "%{decrypted|encrypt(algorithm='aes-128-cbc',key=key)}", ¶ms, &error) == 0, i); table[5].value = str_c(input); - test_assert_idx(var_expand_with_table(output, "%{decrypt;algo=aes-128-cbc,key=%{key}:encrypted2}", table, &error) == 1, i); - test_assert_idx(strcmp(str_c(output), table[4].value)==0, i); + test_assert_idx(var_expand_new(output, "%{encrypted2|decrypt(algorithm='aes-128-cbc',key=key)}", ¶ms, &error) == 0, i); + test_assert_strcmp_idx(str_c(output), table[4].value, i); }; var_expand_crypt_deinit(); diff --git a/src/plugins/var-expand-crypt/var-expand-crypt-plugin.c b/src/plugins/var-expand-crypt/var-expand-crypt-plugin.c index 0de0f7d5fd..3172102d78 100644 --- a/src/plugins/var-expand-crypt/var-expand-crypt-plugin.c +++ b/src/plugins/var-expand-crypt/var-expand-crypt-plugin.c @@ -1,12 +1,8 @@ /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" -#include "array.h" #include "hex-binary.h" -#include "base64.h" #include "str.h" -#include "strescape.h" -#include "var-expand.h" #include "var-expand-private.h" #include "dcrypt.h" @@ -14,18 +10,12 @@ struct module; -enum crypt_field_format { - FORMAT_HEX, - FORMAT_BASE64 -}; - struct var_expand_crypt_context { - struct var_expand_context *ctx; const char *algo; string_t *iv; string_t *enckey; - enum crypt_field_format format; - bool enc_result_only:1; + buffer_t *input; + bool raw; }; static bool var_expand_crypt_initialize(const char **error_r); @@ -35,71 +25,6 @@ void var_expand_crypt_deinit(void); void auth_var_expand_crypt_init(struct module *module); void auth_var_expand_crypt_deinit(void); -static int -var_expand_crypt_settings(struct var_expand_crypt_context *ctx, - const char *const *args, const char **error_r) -{ - while(args != NULL && *args != NULL) { - int ret; - const char *k = t_strcut(*args, '='); - const char *value = strchr(*args, '='); - if (value == NULL) { - args++; - continue; - } else { - value++; - } - - if (strcmp(k, "iv") == 0) { - str_truncate(ctx->iv, 0); - if ((ret = var_expand_with_arrays(ctx->iv, value, - ctx->ctx->tables, - ctx->ctx->funcs, - error_r)) <= 0) { - return ret; - } - const char *hexiv = t_strdup(str_c(ctx->iv)); - /* try to decode IV */ - str_truncate(ctx->iv, 0); - hex_to_binary(hexiv, ctx->iv); - } if (strcmp(k, "noiv") == 0) { - ctx->enc_result_only = strcasecmp(value, "yes")==0; - } if (strcmp(k, "algo") == 0) { - ctx->algo = value; - } else if (strcmp(k, "key") == 0) { - str_truncate(ctx->enckey, 0); - if ((ret = var_expand_with_arrays(ctx->enckey, value, - ctx->ctx->tables, - ctx->ctx->funcs, - error_r)) <= 0) { - return ret; - } - const char *hexkey = t_strdup(str_c(ctx->enckey)); - str_truncate(ctx->enckey, 0); - hex_to_binary(hexkey, ctx->enckey); - } else if (strcmp(k, "format") == 0) { - if (strcmp(value, "hex") == 0) { - ctx->format = FORMAT_HEX; - } else if (strcmp(value, "base64") == 0) { - ctx->format = FORMAT_BASE64; - } else { - *error_r = t_strdup_printf( - "Cannot parse hash arguments:" - "'%s' is not supported format", - value); - return -1; - } - } - args++; - } - - if (ctx->algo == NULL) { - ctx->algo = VAR_EXPAND_CRYPT_DEFAULT_ALGO; - } - - return 1; -} - static int var_expand_crypt(struct dcrypt_context_symmetric *dctx, buffer_t *key, buffer_t *iv, const buffer_t *input, buffer_t *output, const char **error_r) @@ -110,7 +35,7 @@ var_expand_crypt(struct dcrypt_context_symmetric *dctx, buffer_t *key, buffer_t /* acquire IV */ dcrypt_ctx_sym_get_iv(dctx, iv); } else if (dcrypt_ctx_sym_get_iv_length(dctx) != iv->used) { - *error_r = t_strdup_printf("crypt: IV length invalid (%zu != %u)", + *error_r = t_strdup_printf("IV length invalid (%zu != %u)", iv->used, dcrypt_ctx_sym_get_iv_length(dctx)); return -1; @@ -119,7 +44,7 @@ var_expand_crypt(struct dcrypt_context_symmetric *dctx, buffer_t *key, buffer_t } if (dcrypt_ctx_sym_get_key_length(dctx) != key->used) { - *error_r = t_strdup_printf("crypt: Key length invalid (%zu != %u)", + *error_r = t_strdup_printf("Key length invalid (%zu != %u)", key->used, dcrypt_ctx_sym_get_key_length(dctx)); return -1; @@ -135,178 +60,143 @@ var_expand_crypt(struct dcrypt_context_symmetric *dctx, buffer_t *key, buffer_t return 0; } -static int -var_expand_encrypt(struct var_expand_context *_ctx, - const char *key, const char *field, - const char **result_r, const char **error_r) +static int var_expand_crypt_settings(struct var_expand_state *state, + const struct var_expand_statement *stmt, + struct var_expand_crypt_context *ctx, + const char **error_r) { - if (!var_expand_crypt_initialize(error_r)) - return -1; + const char *iv; + + ctx->iv = t_buffer_create(32); + ctx->enckey = t_buffer_create(32); + ctx->algo = VAR_EXPAND_CRYPT_DEFAULT_ALGO; + + struct var_expand_parameter_iter_context *iter = + var_expand_parameter_iter_init(stmt); + while (var_expand_parameter_iter_more(iter)) { + const struct var_expand_parameter *par = + var_expand_parameter_iter_next(iter); + + const char *key = var_expand_parameter_key(par); + if (key == NULL) + ERROR_TOO_MANY_UNNAMED_PARAMETERS; + else if (strcmp(key, "algorithm") == 0) { + if (var_expand_parameter_string_or_var(state, par, + &ctx->algo, error_r) < 0) + return -1; + } else if (strcmp(key, "iv") == 0) { + if (var_expand_parameter_string_or_var(state, par, &iv, + error_r) < 0) { + return -1; + } + hex_to_binary(iv, ctx->iv); + } else if (strcmp(key, "key") == 0) { + const char *enckey; + if (var_expand_parameter_string_or_var(state, par, &enckey, + error_r) < 0) { + return -1; + } + hex_to_binary(enckey, ctx->enckey); + } else if (strcmp(key, "raw") == 0) { + if (var_expand_parameter_bool_or_var(state, par, &ctx->raw, + error_r) < 0) + return -1; + } else + ERROR_UNSUPPORTED_KEY(key); + } - const char *p = strchr(key, ';'); - const char *const *args = NULL; - const char *value; - struct var_expand_crypt_context ctx; - string_t *dest; - int ret = 0; + ERROR_IF_NO_TRANSFER_TO(stmt->function); - memset(&ctx, 0, sizeof(ctx)); - ctx.ctx = _ctx; - ctx.format = FORMAT_HEX; + ctx->input = state->transfer; + if (ctx->raw || strcmp(stmt->function, "encrypt") == 0) + return 0; - if (p != NULL) { - args = t_strsplit(p+1, ","); + /* handle $ separated input, only support hex */ + const char *const *parts = t_strsplit(str_c(state->transfer), "$"); + if (str_array_length(parts) == 3 && *parts[2] == '\0') { + if (ctx->iv->used > 0) { + *error_r = "Cannot have iv in parameter and input"; + return -1; + } + hex_to_binary(parts[0], ctx->iv); + ctx->input = t_buffer_create(strlen(parts[1]) / 2); + hex_to_binary(parts[1], ctx->input); + } else { + *error_r = "Invalid input format"; + return -1; } - string_t *field_value = t_str_new(64); - ctx.iv = t_str_new(64); - ctx.enckey = t_str_new(64); - string_t *tmp = t_str_new(128); - - if ((ret = var_expand_long(_ctx, field, strlen(field), - &value, error_r)) <= 0) { - return ret; - } + return 0; - if (*value == '\0') { - *result_r = value; - return ret; - } +} - if ((ret = var_expand_crypt_settings(&ctx, args, error_r)) <= 0) - return ret; +static int +var_expand_encrypt(const struct var_expand_statement *stmt, + struct var_expand_state *state, const char **error_r) +{ + if (!var_expand_crypt_initialize(error_r)) + return -1; - str_append(field_value, value); + struct var_expand_crypt_context ctx; + i_zero(&ctx); + if (var_expand_crypt_settings(state, stmt, &ctx, error_r) < 0) + return -1; struct dcrypt_context_symmetric *dctx; if (!dcrypt_ctx_sym_create(ctx.algo, DCRYPT_MODE_ENCRYPT, &dctx, error_r)) return -1; + buffer_t *dest = t_buffer_create(state->transfer->used*2); - ret = var_expand_crypt(dctx, ctx.enckey, ctx.iv, field_value, tmp, error_r); + int ret = var_expand_crypt(dctx, ctx.enckey, ctx.iv, ctx.input, + dest, error_r); dcrypt_ctx_sym_destroy(&dctx); if (ret == 0) { - /* makes compiler happy */ - const char *enciv = NULL; - const char *res = NULL; - - switch(ctx.format) { - case FORMAT_HEX: - enciv = binary_to_hex(ctx.iv->data, ctx.iv->used); - res = binary_to_hex(tmp->data, tmp->used); - break; - case FORMAT_BASE64: - dest = t_str_new(32); - base64_encode(ctx.iv->data, ctx.iv->used, dest); - enciv = str_c(dest); - dest = t_str_new(32); - base64_encode(tmp->data, tmp->used, dest); - res = str_c(dest); - break; - default: - i_unreached(); + if (ctx.raw) + var_expand_state_set_transfer_binary(state, dest->data, dest->used); + else { + state->transfer_set = TRUE; + str_truncate(state->transfer, 0); + binary_to_hex_append(state->transfer, ctx.iv->data, ctx.iv->used); + str_append_c(state->transfer, '$'); + binary_to_hex_append(state->transfer, dest->data, dest->used); + str_append_c(state->transfer, '$'); } - if (ctx.enc_result_only) - *result_r = t_strdup(res); - else - *result_r = t_strdup_printf("%s$%s$", enciv, res); - ret = 1; } return ret; } static int -var_expand_decrypt(struct var_expand_context *_ctx, - const char *key, const char *field, - const char **result_r, const char **error_r) +var_expand_decrypt(const struct var_expand_statement *stmt, + struct var_expand_state *state, const char **error_r) + { if (!var_expand_crypt_initialize(error_r)) return -1; - const char *p = strchr(key, ';'); - const char *const *args = NULL; - const char *value; struct var_expand_crypt_context ctx; - int ret = 0; - - memset(&ctx, 0, sizeof(ctx)); - ctx.ctx = _ctx; - ctx.format = FORMAT_HEX; - - if (p != NULL) { - args = t_strsplit(p+1, ","); - } - - string_t *field_value = t_str_new(64); - ctx.iv = t_str_new(64); - ctx.enckey = t_str_new(64); - string_t *tmp = t_str_new(128); - - if ((ret = var_expand_long(_ctx, field, strlen(field), - &value, error_r)) <= 0) { - return ret; - } - - if (*value == '\0') { - *result_r = value; - return ret; - } - - if ((ret = var_expand_crypt_settings(&ctx, args, error_r)) <= 0) - return ret; - - const char *encdata = value; - const char *enciv = ""; - - /* make sure IV is correct */ - if (ctx.iv->used == 0 && (p = strchr(encdata, '$')) != NULL) { - /* see if IV can be taken from data */ - enciv = t_strcut(encdata, '$'); - encdata = t_strcut(p+1,'$'); - } - - str_truncate(field_value, 0); - - /* try to decode iv and encdata */ - switch(ctx.format) { - case FORMAT_HEX: - if (ctx.iv->used == 0) - hex_to_binary(enciv, ctx.iv); - hex_to_binary(encdata, field_value); - break; - case FORMAT_BASE64: - if (ctx.iv->used == 0) - str_append_str(ctx.iv, t_base64_decode_str(enciv)); - str_append_str(field_value, t_base64_decode_str(encdata)); - break; - } - - if (ctx.iv->used == 0) { - *error_r = t_strdup_printf("decrypt: IV missing"); + i_zero(&ctx); + if (var_expand_crypt_settings(state, stmt, &ctx, error_r) < 0) return -1; - } struct dcrypt_context_symmetric *dctx; if (!dcrypt_ctx_sym_create(ctx.algo, DCRYPT_MODE_DECRYPT, &dctx, error_r)) return -1; - ret = var_expand_crypt(dctx, ctx.enckey, ctx.iv, field_value, tmp, error_r); + string_t *dest = t_buffer_create(state->transfer->used / 2); + int ret = var_expand_crypt(dctx, ctx.enckey, ctx.iv, ctx.input, + dest, error_r); dcrypt_ctx_sym_destroy(&dctx); if (ret == 0) { - *result_r = str_c(tmp); - ret = 1; + if (memchr(dest->data, '\0', dest->used) != NULL) + var_expand_state_set_transfer_binary(state, dest->data, dest->used); + else + var_expand_state_set_transfer(state, str_c(dest)); } - return ret; } -static const struct var_expand_extension_func_table funcs[] = { - { "encrypt", var_expand_encrypt }, - { "decrypt", var_expand_decrypt }, - { NULL, NULL, } -}; - static bool var_expand_crypt_initialize(const char **error_r) { return dcrypt_initialize(NULL, NULL, error_r); @@ -314,15 +204,17 @@ static bool var_expand_crypt_initialize(const char **error_r) void var_expand_crypt_init(struct module *module ATTR_UNUSED) { - var_expand_register_func_array(funcs); /* do not initialize dcrypt here - saves alot of memory to not load openssl every time. Only load it if needed */ + var_expand_register_filter("encrypt", var_expand_encrypt); + var_expand_register_filter("decrypt", var_expand_decrypt); } void var_expand_crypt_deinit(void) { - var_expand_unregister_func_array(funcs); + var_expand_unregister_filter("encrypt"); + var_expand_unregister_filter("decrypt"); } void auth_var_expand_crypt_init(struct module *module)