bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "lib.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "array.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "hex-binary.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "base64.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "str.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "strescape.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "var-expand.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "var-expand-private.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#include "dcrypt.h"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi#define VAR_EXPAND_CRYPT_DEFAULT_ALGO "AES-256-CBC"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistruct module;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomienum crypt_field_format {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi FORMAT_HEX,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi FORMAT_BASE64
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi};
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistruct var_expand_crypt_context {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi struct var_expand_context *ctx;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *algo;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi string_t *iv;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi string_t *enckey;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi enum crypt_field_format format;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi bool enc_result_only:1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi};
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
5d2c15eaba4920cb6556be2c735fdb3f79655abaAki Tuomistatic bool var_expand_crypt_initialize(const char **error_r);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid var_expand_crypt_init(struct module *module);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid var_expand_crypt_deinit(void);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid auth_var_expand_crypt_init(struct module *module);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid auth_var_expand_crypt_deinit(void);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistatic bool has_been_init;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistatic int
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivar_expand_crypt_settings(struct var_expand_crypt_context *ctx,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *const *args, const char **error_r)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi while(args != NULL && *args != NULL) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *k = t_strcut(*args, '=');
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *value = strchr(*args, '=');
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (value == NULL) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi args++;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi continue;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi value++;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (strcmp(k, "iv") == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_truncate(ctx->iv, 0);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (var_expand_with_funcs(ctx->iv, value, ctx->ctx->table,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->ctx->func_table,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->ctx->context, error_r) < 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *hexiv = t_strdup(str_c(ctx->iv));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* try to decode IV */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_truncate(ctx->iv, 0);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi hex_to_binary(hexiv, ctx->iv);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } if (strcmp(k, "noiv") == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->enc_result_only = strcasecmp(value, "yes")==0;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } if (strcmp(k, "algo") == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->algo = value;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else if (strcmp(k, "key") == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_truncate(ctx->enckey, 0);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (var_expand_with_funcs(ctx->enckey, value,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->ctx->table,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->ctx->func_table,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->ctx->context,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi error_r) < 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *hexkey = t_strdup(str_c(ctx->enckey));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_truncate(ctx->enckey, 0);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi hex_to_binary(hexkey, ctx->enckey);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else if (strcmp(k, "format") == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (strcmp(value, "hex") == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->format = FORMAT_HEX;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else if (strcmp(value, "base64") == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->format = FORMAT_BASE64;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *error_r = t_strdup_printf(
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi "Cannot parse hash arguments:"
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi "'%s' is not supported format",
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi value);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi args++;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (ctx->algo == NULL) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx->algo = "AES-256-CBC";
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return 0;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistatic int
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivar_expand_crypt(struct dcrypt_context_symmetric *dctx, buffer_t *key, buffer_t *iv,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const buffer_t *input, buffer_t *output, const char **error_r)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* make sure IV is correct */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (iv->used == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_set_key_iv_random(dctx);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* acquire IV */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_get_iv(dctx, iv);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else if (dcrypt_ctx_sym_get_iv_length(dctx) != iv->used) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *error_r = t_strdup_printf("crypt: IV length invalid (%"PRIuSIZE_T" != %u)",
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi iv->used,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_get_iv_length(dctx));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_set_iv(dctx, iv->data, iv->used);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (dcrypt_ctx_sym_get_key_length(dctx) != key->used) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *error_r = t_strdup_printf("crypt: Key length invalid (%"PRIuSIZE_T" != %u)",
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi key->used,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_get_key_length(dctx));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi } else {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_set_key(dctx, key->data, key->used);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (!dcrypt_ctx_sym_init(dctx, error_r) ||
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi !dcrypt_ctx_sym_update(dctx, input->data,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi input->used, output, error_r) ||
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi !dcrypt_ctx_sym_final(dctx, output, error_r))
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return 0;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistatic int
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivar_expand_encrypt(struct var_expand_context *_ctx,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *key, const char *field,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char **result_r, const char **error_r)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
5d2c15eaba4920cb6556be2c735fdb3f79655abaAki Tuomi if (!has_been_init && !var_expand_crypt_initialize(error_r))
5d2c15eaba4920cb6556be2c735fdb3f79655abaAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *p = strchr(key, ';');
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *const *args = NULL;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *value;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi struct var_expand_crypt_context ctx;
9e38412ec12ae8dc4f67ade5b18c8b976de59bcbAki Tuomi string_t *dest;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi int ret = 0;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi memset(&ctx, 0, sizeof(ctx));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.ctx = _ctx;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.format = FORMAT_HEX;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (p != NULL) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi args = t_strsplit(p+1, ",");
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi string_t *field_value = t_str_new(64);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.iv = t_str_new(64);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.enckey = t_str_new(64);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi string_t *tmp = t_str_new(128);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if ((ret = var_expand_long(_ctx, field, strlen(field),
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi &value, error_r)) < 1) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return ret;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (*value == '\0') {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *result_r = value;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return ret;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (var_expand_crypt_settings(&ctx, args, error_r) < 0)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_append(field_value, value);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi struct dcrypt_context_symmetric *dctx;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (!dcrypt_ctx_sym_create(ctx.algo, DCRYPT_MODE_ENCRYPT, &dctx, error_r))
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ret = var_expand_crypt(dctx, ctx.enckey, ctx.iv, field_value, tmp, error_r);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_destroy(&dctx);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (ret == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* makes compiler happy */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *enciv = "";
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *res = "";
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi switch(ctx.format) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi case FORMAT_HEX:
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi enciv = binary_to_hex(ctx.iv->data, ctx.iv->used);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi res = binary_to_hex(tmp->data, tmp->used);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi break;
9e38412ec12ae8dc4f67ade5b18c8b976de59bcbAki Tuomi case FORMAT_BASE64:
9e38412ec12ae8dc4f67ade5b18c8b976de59bcbAki Tuomi dest = t_str_new(32);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi base64_encode(ctx.iv->data, ctx.iv->used, dest);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi enciv = str_c(dest);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dest = t_str_new(32);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi base64_encode(tmp->data, tmp->used, dest);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi res = str_c(dest);
9e38412ec12ae8dc4f67ade5b18c8b976de59bcbAki Tuomi break;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi default:
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi i_unreached();
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (ctx.enc_result_only)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *result_r = t_strdup(res);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi else
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *result_r = t_strdup_printf("%s$%s$", enciv, res);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ret = 1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return ret;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistatic int
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivar_expand_decrypt(struct var_expand_context *_ctx,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *key, const char *field,
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char **result_r, const char **error_r)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
5d2c15eaba4920cb6556be2c735fdb3f79655abaAki Tuomi if (!has_been_init && !var_expand_crypt_initialize(error_r))
5d2c15eaba4920cb6556be2c735fdb3f79655abaAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *p = strchr(key, ';');
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *const *args = NULL;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi const char *value;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi struct var_expand_crypt_context ctx;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi int ret = 0;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi memset(&ctx, 0, sizeof(ctx));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.ctx = _ctx;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.format = FORMAT_HEX;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (p != NULL) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi args = t_strsplit(p+1, ",");
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi string_t *field_value = t_str_new(64);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.iv = t_str_new(64);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ctx.enckey = t_str_new(64);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi string_t *tmp = t_str_new(128);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if ((ret = var_expand_long(_ctx, field, strlen(field),
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi &value, error_r)) < 1) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return ret;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (*value == '\0') {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *result_r = value;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return ret;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (var_expand_crypt_settings(&ctx, args, error_r) < 0)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
e8d8cff110f7a194c18abda75a07e9f15bc9fa44Aki Tuomi const char *encdata = value;
e8d8cff110f7a194c18abda75a07e9f15bc9fa44Aki Tuomi const char *enciv = "";
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* make sure IV is correct */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (ctx.iv->used == 0 && (p = strchr(encdata, '$')) != NULL) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* see if IV can be taken from data */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi enciv = t_strcut(encdata, '$');
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi encdata = t_strcut(p+1,'$');
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_truncate(field_value, 0);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* try to decode iv and encdata */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi switch(ctx.format) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi case FORMAT_HEX:
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (ctx.iv->used == 0)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi hex_to_binary(enciv, ctx.iv);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi hex_to_binary(encdata, field_value);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi break;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi case FORMAT_BASE64:
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (ctx.iv->used == 0)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_append_str(ctx.iv, t_base64_decode_str(enciv));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi str_append_str(field_value, t_base64_decode_str(encdata));
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi break;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (ctx.iv->used == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *error_r = t_strdup_printf("decrypt: IV missing");
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi struct dcrypt_context_symmetric *dctx;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (!dcrypt_ctx_sym_create(ctx.algo, DCRYPT_MODE_DECRYPT, &dctx, error_r))
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return -1;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi ret = var_expand_crypt(dctx, ctx.enckey, ctx.iv, field_value, tmp, error_r);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_ctx_sym_destroy(&dctx);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
e8d8cff110f7a194c18abda75a07e9f15bc9fa44Aki Tuomi if (ret == 0) {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi *result_r = str_c(tmp);
e8d8cff110f7a194c18abda75a07e9f15bc9fa44Aki Tuomi ret = 1;
e8d8cff110f7a194c18abda75a07e9f15bc9fa44Aki Tuomi }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi return ret;
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomistatic const struct var_expand_extension_func_table funcs[] = {
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi { "encrypt", var_expand_encrypt },
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi { "decrypt", var_expand_decrypt },
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi { NULL, NULL, }
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi};
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
5d2c15eaba4920cb6556be2c735fdb3f79655abaAki Tuomistatic bool var_expand_crypt_initialize(const char **error_r)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
5d2c15eaba4920cb6556be2c735fdb3f79655abaAki Tuomi return dcrypt_initialize(NULL, NULL, error_r);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid var_expand_crypt_init(struct module *module ATTR_UNUSED)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi var_expand_register_func_array(funcs);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi /* do not initialize dcrypt here - saves alot of memory
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi to not load openssl every time. Only load it if
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi needed */
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid var_expand_crypt_deinit(void)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi var_expand_unregister_func_array(funcs);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi if (has_been_init)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi dcrypt_deinitialize();
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid auth_var_expand_crypt_init(struct module *module)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi var_expand_crypt_init(module);
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomivoid auth_var_expand_crypt_deinit(void)
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi{
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi var_expand_crypt_deinit();
dbc351d8a8dad8cfbc0c1f5d957d23873ab5e26cAki Tuomi}